static void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping) { int i; for (i = 0; i < MAX_OTHER_SERVERS; i++) { if (NET_CompareAdr(from, cls.localServers[i].adr)) { CL_SetServerInfo(&cls.localServers[i], info, ping); } } for (i = 0; i < MAX_OTHER_SERVERS; i++) { if (NET_CompareAdr(from, cls.mplayerServers[i].adr)) { CL_SetServerInfo(&cls.mplayerServers[i], info, ping); } } for (i = 0; i < MAX_GLOBAL_SERVERS; i++) { if (NET_CompareAdr(from, cls.globalServers[i].adr)) { CL_SetServerInfo(&cls.globalServers[i], info, ping); } } for (i = 0; i < MAX_OTHER_SERVERS; i++) { if (NET_CompareAdr(from, cls.favoriteServers[i].adr)) { CL_SetServerInfo(&cls.favoriteServers[i], info, ping); } } }
int LAN_AddFavAddr( const char *address ) { if ( cls.numfavoriteservers < MAX_OTHER_SERVERS ) { netadr_t adr; if ( !NET_StringToAdr( address, &adr ) ) { return 2; } if ( adr.type == NA_BAD ) { return 3; } for ( int i = 0; i < cls.numfavoriteservers; i++ ) { if ( NET_CompareAdr( cls.favoriteServers[i].adr, adr ) ) { return 0; } } cls.favoriteServers[cls.numfavoriteservers].adr = adr; Q_strncpyz( cls.favoriteServers[cls.numfavoriteservers].hostName, address, sizeof(cls.favoriteServers[cls.numfavoriteservers].hostName) ); cls.favoriteServers[cls.numfavoriteservers].visible = qtrue; cls.numfavoriteservers++; return 1; } return -1; }
void Master_AddServer(netadr_t *adr) { master_server_t *ptr; Master_Init(); ptr = masterlist; //Is it already listed? while(ptr != NULL) { if(NET_CompareAdr(ptr->address, *adr) != 0) { return; } ptr = ptr->next; } //Not found, make a new entry. ptr = (master_server_t *)Q_Malloc(sizeof(master_server_t)); if(ptr == NULL) { //malloc failure. Just back away and let some other function handle it... return; } ptr->address = *adr; ptr->last_heartbeat = -15; ptr->next = masterlist; masterlist = ptr; }
/* ======================= LAN_ServerIsInFavoriteList ======================= */ qboolean LAN_ServerIsInFavoriteList( int source, int n ) { int i; serverInfo_t *server = NULL; switch ( source ) { case AS_LOCAL: if ( n >= 0 && n < MAX_OTHER_SERVERS ) { server = &cls.localServers[n]; } break; case AS_GLOBAL: if ( n >= 0 && n < MAX_GLOBAL_SERVERS ) { server = &cls.globalServers[n]; } break; case AS_FAVORITES: if ( n >= 0 && n < MAX_OTHER_SERVERS ) { return qtrue; } break; } if ( !server ) { return qfalse; } for ( i = 0; i < cls.numfavoriteservers; i++ ) { if ( NET_CompareAdr( cls.favoriteServers[i].adr, server->adr ) ) { return qtrue; } } return qfalse; }
bool operator==(const netadr_t &a, const netadr_t &b) { if (a.type != b.type) { return false; } return NET_CompareAdr(&a, &b); }
/* ==================== LAN_RemoveServer ==================== */ static void LAN_RemoveServer(int source, const char *addr) { int *count, i; serverInfo_t *servers = NULL; count = NULL; switch (source) { case AS_LOCAL : count = &cls.numlocalservers; servers = &cls.localServers[0]; break; case AS_MPLAYER: case AS_GLOBAL : count = &cls.numglobalservers; servers = &cls.globalServers[0]; break; case AS_FAVORITES : count = &cls.numfavoriteservers; servers = &cls.favoriteServers[0]; break; } if (servers) { netadr_t comp; NET_StringToAdr( addr, &comp ); for (i = 0; i < *count; i++) { if (NET_CompareAdr( comp, servers[i].adr)) { int j = i; while (j < *count - 1) { Com_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j])); j++; } (*count)--; break; } } } }
/* =================== CL_UpdateInfoPacket =================== */ void CL_UpdateInfoPacket(netadr_t from) { if (autoupdate.autoupdateServer.type == NA_BAD) { Com_DPrintf("CL_UpdateInfoPacket: Update server has bad address\n"); return; } Com_DPrintf("Update server resolved to %s\n", NET_AdrToString(autoupdate.autoupdateServer)); if (!NET_CompareAdr(from, autoupdate.autoupdateServer)) { // TODO: when the updater is server-side as well, write this message to the Attack log Com_DPrintf("CL_UpdateInfoPacket: Ignoring packet from %s, because the update server is located at %s\n", NET_AdrToString(from), NET_AdrToString(autoupdate.autoupdateServer)); return; } Cvar_Set("com_updateavailable", Cmd_Argv(1)); if (!Q_stricmp(com_updateavailable->string, "1")) { Cvar_Set("com_updatefiles", Cmd_Argv(2)); #ifdef FEATURE_AUTOUPDATE VM_Call(uivm, UI_SET_ACTIVE_MENU, UIMENU_WM_AUTOUPDATE); #endif /* FEATURE_AUTOUPDATE */ } }
static void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping) { int i; int count; serverInfo_t *server = NULL; switch (cls.pingUpdateSource) { case 0: server = &cls.historyServers[0]; count = cls.numhistoryservers; break; case 1: server = &cls.globalServers[0]; count = cls.numglobalservers; break; case 2: server = &cls.favoriteServers[0]; count = cls.numfavoriteservers; break; } for (i = 0; i < count; i++) { if (NET_CompareAdr(from, server[i].adr)) { CL_SetServerInfo(&server[i], info, ping); } } }
//=========================================================================== // GameConsoleCommand //=========================================================================== void PR2_GameConsoleCommand(void) { int old_other, old_self; client_t *cl; int i; if( sv_vm ) { old_self = pr_global_struct->self; old_other = pr_global_struct->other; pr_global_struct->other = 0; //sv_cmd = SV_CMD_CONSOLE; pr_global_struct->self = 0; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (!cl->state) continue; if ( cl->isBot ) continue; if (NET_CompareAdr(cl->netchan.remote_address, net_from)) { pr_global_struct->self = EDICT_TO_PROG(cl->edict); break; } } VM_Call(sv_vm, GAME_CONSOLE_COMMAND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); pr_global_struct->self = old_self; pr_global_struct->other = old_other; } }
/* =================== CL_GetServerStatus =================== */ serverStatus_t *CL_GetServerStatus( netadr_t from ) { serverStatus_t *serverStatus; int i, oldest, oldestTime; serverStatus = NULL; for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) { if ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) { return &cl_serverStatusList[i]; } } for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) { if ( cl_serverStatusList[i].retrieved ) { return &cl_serverStatusList[i]; } } oldest = -1; oldestTime = 0; for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) { if (oldest == -1 || cl_serverStatusList[i].startTime < oldestTime) { oldest = i; oldestTime = cl_serverStatusList[i].startTime; } } if (oldest != -1) { return &cl_serverStatusList[oldest]; } serverStatusCount++; return &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)]; }
/* ================= CL_PacketEvent A packet has arrived from the main event loop ================= */ void CL_PacketEvent( netadr_t from, msg_t *msg ) { clc.lastPacketTime = cls.realtime; if ( msg->cursize >= 4 && *(int *)msg->data == -1 ) { CL_ConnectionlessPacket( from, msg ); return; } if ( cls.state < CA_CONNECTED ) { return; // can't be a valid sequenced packet } if ( msg->cursize < 8 ) { Com_Printf ("%s: Runt packet\n",NET_AdrToString( from )); return; } // // packet from server // if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) { Com_DPrintf ("%s:sequenced packet without connection\n" ,NET_AdrToString( from ) ); // FIXME: send a client disconnect? return; } if (!Netchan_Process( &clc.netchan, msg) ) { return; // out of order, duplicated, etc } clc.lastPacketTime = cls.realtime; CL_ParseServerMessage( msg ); }
void OnPacketTV() { if(NET_CompareAdr(net_from, net_server)) { buf_t out = net_message; // if this is a server connect message, keep a copy for other clients int t = net_message.ReadLong(); if(t == CHALLENGE) { std::cout << "first client connected" << std::endl; challenge_message = net_message; } else if(t == 0) { first_message = net_message; buf_t tmp; tr.Go(net_message, tmp); } else { out.clear(); out.WriteLong(t); tr.Go(net_message, out); } // replicate server packet to all connected clients for(int i = 0; i < spectators.size(); i++) { NET_SendPacket(out.cursize, out.data, spectators[i]); } } else { // is this an existing client? for(int i = 0; i < spectators.size(); i++) { if(NET_CompareAdr(net_from, spectators[i])) { OnClientTV(i); return; } } // must be a new client OnNewClientTV(); } }
/* ================= CL_ReadNetMessage ================= */ void CL_ReadNetMessage( void ) { size_t curSize; while( CL_GetMessage( net_message_buffer, &curSize )) { BF_Init( &net_message, "ServerData", net_message_buffer, curSize ); // check for connectionless packet (0xffffffff) first if( BF_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 ) { CL_ConnectionlessPacket( net_from, &net_message ); continue; } // can't be a valid sequenced packet if( cls.state < ca_connected ) continue; if( BF_GetMaxBytes( &net_message ) < 8 ) { MsgDev( D_WARN, "%s: runt packet\n", NET_AdrToString( net_from )); continue; } // packet from server if( !cls.demoplayback && !NET_CompareAdr( net_from, cls.netchan.remote_address )) { MsgDev( D_ERROR, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from )); continue; } if( !cls.demoplayback && !Netchan_Process( &cls.netchan, &net_message )) continue; // wasn't accepted for some reason CL_ParseServerMessage( &net_message ); } // check for fragmentation/reassembly related packets. if( cls.state != ca_disconnected && Netchan_IncomingReady( &cls.netchan )) { // the header is different lengths for reliable and unreliable messages int headerBytes = BF_GetNumBytesRead( &net_message ); // process the incoming buffer(s) if( Netchan_CopyNormalFragments( &cls.netchan, &net_message )) { CL_ParseServerMessage( &net_message ); } if( Netchan_CopyFileFragments( &cls.netchan, &net_message )) { // remove from resource request stuff. CL_ProcessFile( true, cls.netchan.incomingfilename ); } } Netchan_UpdateProgress( &cls.netchan ); }
void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { int i, type; //->char info[1024]; char* str; char *infoString; //->int prot; infoString = MSG_ReadString( msg ); //infoString = msg->data; // if this isn't the correct protocol version, ignore it /*prot = atoi( Info_ValueForKey( infoString, "protocol" ) ); if ( prot != 144 ) { Com_DPrintf( "Different protocol info packet: %s\n", infoString ); return; }*/ const char* challenge = Info_ValueForKey(infoString, "challenge"); if (challenge && !_strnicmp("_join", challenge, 5)) { CL_JoinResponse(from, infoString); } // iterate servers waiting for ping response for (i=0; i<MAX_PINGREQUESTS; i++) { if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) ) { // calc ping time cl_pinglist[i].time = timeGetTime() - cl_pinglist[i].start + 1; //Com_Printf( 0, "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) ); // save of info strncpy( cl_pinglist[i].info, infoString, sizeof( cl_pinglist[i].info ) ); // tack on the net type // NOTE: make sure these types are in sync with the netnames strings in the UI switch (from.type) { case NA_BROADCAST: case NA_IP: str = "udp"; type = 1; break; default: str = "???"; type = 0; break; } Info_SetValueForKey( cl_pinglist[i].info, "nettype", va("%d", type) ); CL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time); return; } } }
/* =================== CL_ServerStatus =================== */ int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen ) { int i; netadr_t to; serverStatus_t *serverStatus; // if no server address then reset all server status requests if ( !serverAddress ) { for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) { cl_serverStatusList[i].address.port = 0; cl_serverStatusList[i].retrieved = qtrue; } return qfalse; } // get the address if ( !NET_StringToAdr( serverAddress, &to ) ) { return qfalse; } serverStatus = CL_GetServerStatus( to ); // if no server status string then reset the server status request for this address if ( !serverStatusString ) { serverStatus->retrieved = qtrue; return qfalse; } // if this server status request has the same address if ( NET_CompareAdr( to, serverStatus->address) ) { // if we recieved an response for this server status request if (!serverStatus->pending) { Q_strncpyz(serverStatusString, serverStatus->string, maxLen); serverStatus->retrieved = qtrue; serverStatus->startTime = 0; return qtrue; } // resend the request regularly else if ( serverStatus->startTime < Com_Milliseconds() - cl_serverStatusResendTime->integer ) { serverStatus->print = qfalse; serverStatus->pending = qtrue; serverStatus->retrieved = qfalse; serverStatus->time = 0; serverStatus->startTime = Com_Milliseconds(); NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" ); return qfalse; } } // if retrieved else if ( serverStatus->retrieved ) { serverStatus->address = to; serverStatus->print = qfalse; serverStatus->pending = qtrue; serverStatus->retrieved = qfalse; serverStatus->startTime = Com_Milliseconds(); serverStatus->time = 0; NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" ); return qfalse; } return qfalse; }
qbool NET_SendTCPPacket_SV (netsrc_t netsrc, int length, void *data, netadr_t to) { svtcpstream_t *st; if (netsrc != NS_SERVER) return false; for (st = svs.tcpstreams; st; st = st->next) { if (st->socketnum == INVALID_SOCKET) continue; if (NET_CompareAdr(to, st->remoteaddr)) { int sent; unsigned short slen = BigShort((unsigned short)length); if (st->outlen + length + sizeof(slen) >= sizeof(st->outbuffer)) { // not enough space, we overflowed break; // well, quake should resist to some packet lost.. so we just drop that packet. } // put data in buffer memmove(st->outbuffer + st->outlen, (char*)&slen, sizeof(slen)); st->outlen += sizeof(slen); memmove(st->outbuffer + st->outlen, data, length); st->outlen += length; sent = send(st->socketnum, st->outbuffer, st->outlen, 0); if (sent == 0) { // think it's OK } else if (sent > 0) //we put some data through { //move up the buffer st->outlen -= sent; memmove(st->outbuffer, st->outbuffer + sent, st->outlen); } else { //error of some kind. would block or something if (qerrno != EWOULDBLOCK && qerrno != EAGAIN) { st->drop = true; // something cricial, drop than } } break; } } // 'st' will be not zero, if we found 'to' in 'svs.tcpstreams'. // That does not mean we actualy send packet, since there case of overflow, but who cares, // all is matter that we found such 'to' and tried to send packet. return !!st; }
/* ================= SV_GetChallenge A "getchallenge" OOB command has been received Returns a challenge number that can be used in a subsequent connectResponse command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. If we are authorizing, a challenge request will cause a packet to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. ================= */ void SV_GetChallenge( netadr_t from ) { int i; int oldest; int oldestTime; challenge_t *challenge; // ignore if we are in single player if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { return; } oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip challenge = &svs.challenges[0]; for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) { break; } if ( challenge->time < oldestTime ) { oldestTime = challenge->time; oldest = i; } } if (i == MAX_CHALLENGES) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; i = oldest; } // if they are on a lan address, send the challengeResponse immediately /*if ( Sys_IsLANAddress( from ) ) { challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); return; }*/ // if they have been challenging for a long time and we // haven't heard anything from the authorize server, go ahead and // let them in, assuming the id server is down if ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) { Com_DPrintf( "authorize server timed out\n" ); challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i", challenge->challenge ); return; } }
/* ===================== SV_DropClient Called when the player is totally leaving the server, either willingly or unwillingly. This is NOT called if the entire server is quiting or crashing -- SV_FinalMessage() will handle that ===================== */ void SV_DropClient( client_t *drop, const char *reason ) { int i; challenge_t *challenge; if ( drop->state == CS_ZOMBIE ) { return; // already dropped } // see if we already have a challenge for this ip challenge = &svs.challenges[0]; for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { challenge->connected = qfalse; break; } } // Kill any download SV_CloseDownload( drop ); // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); if (drop->download) { FS_FCloseFile( drop->download ); drop->download = 0; } // call the prog function for removing a client // this will remove the body, among other things VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients ); // add the disconnect command SV_SendServerCommand( drop, "disconnect \"%s\"", reason); // nuke user info SV_SetUserinfo( drop - svs.clients, "" ); Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); drop->state = CS_ZOMBIE; // become free in a few seconds // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty // send a heartbeat now so the master will get up to date info // if there is already a slot for this ip, reuse it for (i=0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { break; } } if ( i == sv_maxclients->integer ) { SV_Heartbeat_f(); } }
/* ================= SV_GetChallenge A "getchallenge" OOB command has been received Returns a challenge number that can be used in a subsequent connectResponse command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. If we are authorizing, a challenge request will cause a packet to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. ioquake3/openjk: we added a possibility for clients to add a challenge to their packets, to make it more difficult for malicious servers to hi-jack client connections. ================= */ void SV_GetChallenge( netadr_t from ) { int i; int oldest; int oldestTime; int clientChallenge; challenge_t *challenge; // ignore if we are in single player /* if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { return; } */ if (Cvar_VariableValue("ui_singlePlayerActive")) { return; } oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip challenge = &svs.challenges[0]; clientChallenge = atoi(Cmd_Argv(1)); for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if(!challenge->connected && NET_CompareAdr(from, challenge->adr)) { break; } if ( challenge->time < oldestTime ) { oldestTime = challenge->time; oldest = i; } } if (i == MAX_CHALLENGES) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; } // always generate a new challenge number, so the client cannot circumvent sv_maxping challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; challenge->wasrefused = qfalse; challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %i", challenge->challenge, clientChallenge ); }
void SV_BanProcess(client_t* cl, int type, const char* reason) { const char* file = (type == IPBAN) ? "ipbans.txt" : "guidbans.txt"; FILE* f = fopen(file, "a"); if(!f) { Com_Printf("Could not open '%s'.\n", file); return; } challenge_t* challenge; char ip[16]; sprintf(ip, "%d.%d.%d.%d", cl->remoteAddress.ip[0], cl->remoteAddress.ip[1], cl->remoteAddress.ip[2], cl->remoteAddress.ip[3]); int guid = 0; challenge = &challenges[0]; for (int j = 0 ; j < MAX_CHALLENGES ; j++, challenge++ ) { if (NET_CompareAdr( cl->remoteAddress, challenge->adr ) ) { guid = x_challenges[j].guid; break; } } int k; aSingleBan* cur = banlist; while(cur!=NULL) { if((cur->guid == guid && guid != 0 && cur->type == GUIDBAN) || (cur->type == IPBAN && NET_CompareBaseAdr(cl->remoteAddress, cur->adr))) { Com_Printf("%s has already been banned.\n", cl->name); fclose(f); return; } cur=cur->next; } if(!guid && type==GUIDBAN) { Com_Printf("ERROR: You are trying to ban someone with a GUID of zero.\n"); return; } aSingleBan* add = bl_push(); add->type = type; if(type==IPBAN) { add->adr = cl->remoteAddress; fprintf(f, "%s\n", ip); } else if(type == GUIDBAN) { fprintf(f, "%d\n", guid); add->guid = guid; } fclose(f); SV_DropClient(cl, va("Banned: [Reason %s]", reason)); }
/* ==================== LAN_AddServer ==================== */ static int LAN_AddServer(int source, const char *name, const char *address) { int max, *count, i; netadr_t adr; serverInfo_t *servers = NULL; max = MAX_OTHER_SERVERS; count = 0; switch (source) { case AS_LOCAL : count = &cls.numlocalservers; servers = &cls.localServers[0]; break; case AS_MPLAYER : count = &cls.nummplayerservers; servers = &cls.mplayerServers[0]; break; case AS_GLOBAL : max = MAX_GLOBAL_SERVERS; count = &cls.numglobalservers; servers = &cls.globalServers[0]; break; case AS_FAVORITES : count = &cls.numfavoriteservers; servers = &cls.favoriteServers[0]; /* if (!name || !*name) { name = "?"; } */ break; } if (servers && *count < max) { NET_StringToAdr( address, &adr ); if (adr.type == NA_BAD) { return -1; } for ( i = 0; i < *count; i++ ) { if (NET_CompareAdr(servers[i].adr, adr)) { break; } } if (i >= *count) { servers[*count].adr = adr; Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName)); servers[*count].visible = qtrue; (*count)++; return 1; } return 0; } return -1; }
/** * @brief LAN_AddServer * @param[in] source * @param[in] name * @param[in] address * @return */ static int LAN_AddServer(int source, const char *name, const char *address) { int max = MAX_OTHER_SERVERS, *count = 0; netadr_t adr; serverInfo_t *servers = NULL; switch (source) { case AS_LOCAL: count = &cls.numlocalservers; servers = &cls.localServers[0]; break; case AS_GLOBAL: max = MAX_GLOBAL_SERVERS; count = &cls.numglobalservers; servers = &cls.globalServers[0]; break; case AS_FAVORITES: count = &cls.numfavoriteservers; servers = &cls.favoriteServers[0]; break; } if (servers && *count < max) { int i; NET_StringToAdr(address, &adr, NA_UNSPEC); for (i = 0; i < *count; i++) { if (NET_CompareAdr(servers[i].adr, adr)) { break; } } if (i >= *count) { servers[*count].adr = adr; Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName)); servers[*count].visible = qtrue; (*count)++; if (source == AS_FAVORITES) { LAN_SaveServersToFile(); } return 1; } return 0; } return -1; }
/* ================= SV_GetChallenge A "getchallenge" OOB command has been received Returns a challenge number that can be used in a subsequent connectResponse command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. If we are authorizing, a challenge request will cause a packet to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. ================= */ void SV_GetChallenge( netadr_t from ) { int i; int oldest; int oldestTime; challenge_t *challenge; // ignore if we are in single player /* if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { return; } */ if (Cvar_VariableValue("ui_singlePlayerActive")) { return; } oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip challenge = &svs.challenges[0]; for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) { break; } if ( challenge->time < oldestTime ) { oldestTime = challenge->time; oldest = i; } } if (i == MAX_CHALLENGES) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; i = oldest; } // if they are on a lan address, send the challengeResponse immediately if ( Sys_IsLANAddress( from ) ) { challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); return; } }
/* ================== SV_TempBanIsBanned ================== */ qboolean SV_TempBanIsBanned(netadr_t address) { int i; for(i = 0; i < MAX_TEMPBAN_ADDRESSES; i++) { if(svs.tempBanAddresses[i].endtime && svs.tempBanAddresses[i].endtime > svs.time) { if(NET_CompareAdr(address, svs.tempBanAddresses[i].adr)) { return qtrue; } } } return qfalse; }
void SVC_Heartbeat() { master_server_t * ptr; for(ptr = masterlist; ptr != NULL; ptr = ptr->next) { if(NET_CompareAdr(global_net_from, ptr->address) != 0) { ptr->ChallengeRequest = MSG_ReadLong(); Master_RequestHeartbeat(ptr); return; } } }
/* ================= SV_GetChallenge A "getchallenge" OOB command has been received Returns a challenge number that can be used in a subsequent connectResponse command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. ================= */ void SV_GetChallenge( netadr_t from ) { int i; int oldest; int oldestTime; int oldestClientTime; int clientChallenge; challenge_t *challenge; qboolean wasfound = qfalse; oldest = 0; oldestClientTime = oldestTime = 0x7fffffff; // see if we already have a challenge for this ip challenge = &svs.challenges[0]; clientChallenge = atoi(Cmd_Argv(1)); for (i = 0; i < MAX_CHALLENGES; i++, challenge++) { if (!challenge->connected && NET_CompareAdr(from, challenge->adr)) { wasfound = qtrue; if (challenge->time < oldestClientTime) oldestClientTime = challenge->time; } if (wasfound && i >= MAX_CHALLENGES_MULTI) { i = MAX_CHALLENGES; break; } if ( challenge->time < oldestTime ) { oldestTime = challenge->time; oldest = i; } } if (i == MAX_CHALLENGES) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; challenge->clientChallenge = clientChallenge; challenge->adr = from; challenge->connected = qfalse; } // always generate a new challenge number, so the client cannot circumvent sv_maxping challenge->challenge = ((rand() << 16) ^ rand()) ^ svs.time; challenge->wasrefused = qfalse; challenge->time = svs.time; challenge->pingTime = svs.time; NET_OutOfBandPrint(NS_SERVER, challenge->adr, "challengeResponse %i %i", challenge->challenge, clientChallenge); }
/* ================= SV_GetChallenge A "getchallenge" OOB command has been received Returns a challenge number that can be used in a subsequent connectResponse command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. If we are authorizing, a challenge request will cause a packet to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that IP address. ================= */ void SV_GetChallenge( netadr_t from ) { int i; int oldest; int oldestTime; challenge_t *challenge; oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this IP address challenge = &svs.challenges[ 0 ]; for ( i = 0; i < MAX_CHALLENGES; i++, challenge++ ) { if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) { break; } if ( challenge->time < oldestTime ) { oldestTime = challenge->time; oldest = i; } } if ( i == MAX_CHALLENGES ) { // this is the first time this client has asked for a challenge challenge = &svs.challenges[ oldest ]; challenge->challenge = ( ( rand() << 16 ) ^ rand() ) ^ svs.time; challenge->adr = from; challenge->firstTime = svs.time; challenge->firstPing = 0; challenge->time = svs.time; challenge->connected = false; i = oldest; } challenge->pingTime = svs.time; NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "challengeResponse %i", challenge->challenge ); return; }
/* ================== SV_Incognito_f Pretend that you disconnect, but really go to spec. ================== */ static void SV_Incognito_f(void) { client_t *cl; int i; char cmd[64]; // Make sure server is running. if (!com_sv_running->integer) { Com_Printf("Server is not running.\n"); return; } if (!in_redirect) { Com_Printf("The incognito command can only be run through rcon\n"); return; } if (Cmd_Argc() != 1) { Com_Printf("No arguments expected for incognito command\n"); return; } // Find the person connected to server who issued the incognito command. for (i = 0, cl = svs.clients;; i++, cl++) { if (i == sv_maxclients->integer) { cl = NULL; break; } if (cl->state >= CS_ACTIVE && NET_CompareAdr(cl->netchan.remoteAddress, svs.redirectAddress)) { break; // found } } if (cl != NULL) { sv.incognitoJoinSpec = qtrue; Com_sprintf(cmd, sizeof(cmd), "forceteam %i spectator\n", i); Cmd_ExecuteString(cmd); sv.incognitoJoinSpec = qfalse; SV_SendServerCommand(NULL, "print \"%s" S_COLOR_WHITE " disconnected\n\"", cl->name); // color OK Com_sprintf(cmd, sizeof(cmd), "sendclientcommand all cs %i \"\"\n", 548 + i); Cmd_ExecuteString(cmd); } else { Com_Printf("Must be connected to server for incognito to work\n"); } }
qboolean CL_UpdatePacketEvent(netadr_t from) { #ifdef FEATURE_AUTOUPDATE static qboolean autoupdateRedirected = qfalse; // Update server doesn't understand netchan packets if (NET_CompareAdr(autoupdate.autoupdateServer, from) && autoupdate.updateStarted && !autoupdateRedirected) { autoupdateRedirected = qtrue; CL_InitDownloads(); return qtrue; } #endif /* FEATURE_AUTOUPDATE */ return qfalse; }
// // SV_ValidToken // bool SV_IsValidToken(DWORD token) { QWORD now = I_GetTime(); for(size_t i = 0; i < connect_tokens.size(); i++) { if(connect_tokens[i].id == token && NET_CompareAdr(connect_tokens[i].from, net_from) && now - connect_tokens[i].issued < MAX_TOKEN_AGE) { // extend token life and confirm connect_tokens[i].issued = now; return true; } } return false; }