Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/src/content/docs/setup/adding-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ If you skip the `ServerID` step, the plugin will still try to write
bans to the database but with no server-side identity, so the panel
can't tell them apart from bans on other servers.

Servers behind NAT or running in containers may report a private
`hostip`. Set `ServerIP` in the same config to the public IPv4 address
saved in the panel. Leave it blank on servers whose `hostip` already
matches the panel.

## Verifying

Back in the panel's **Servers** page, your new server should show:
Expand Down
12 changes: 12 additions & 0 deletions docs/src/content/docs/setup/plugin-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ The rest of the file controls in-game admin menu behaviour (ban
durations, default reasons, immunity flags, etc.). The defaults are
sensible; tweak as you go.

If the game server runs behind NAT or inside a container, its `hostip`
value may be a private address. Set `ServerIP` to the public IPv4
address registered in the panel:

```ini
"ServerIP" "203.0.113.10"
```

Leave `ServerIP` blank to use `hostip`. This setting controls
address-based server lookup and automatic registration. Keep
`ServerID` set to the panel's numeric ID whenever possible.

After editing either file, **reload the map or restart the game
server** so SourceMod re-reads the configs.

Expand Down
6 changes: 5 additions & 1 deletion game/addons/sourcemod/configs/sourcebans/sourcebans.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@
"ProcessQueueTime" "5"

// Should the plugin automatically add the server to sourcebans
// (servers without -ip being set on startup need this set to 0)
// (servers without -ip being set on startup need this set to 0 unless ServerIP is set)
// (2 = YES ADD WITH RCON, 1 = YES ADD WITHOUT RCON, 0 = DO NOT ADD SERVER)
"AutoAddServer" "0"

// Public IPv4 address registered in the panel when hostip reports a private address
// Leave blank to use the game server's hostip value
"ServerIP" ""

// Enable backing up config files after getting admins from database (1 = enabled, 0 = disabled)
"BackupConfigs" "1"

Expand Down
73 changes: 73 additions & 0 deletions game/addons/sourcemod/scripting/include/sbpp_server_ip.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// *************************************************************************
// This file is part of SourceBans++.
//
// Copyright (C) 2014-2026 SourceBans++ Dev Team <https://github.com/sbpp>
//
// SourceBans++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, per version 3 of the License.
// *************************************************************************

#if defined _sbpp_server_ip_included
#endinput
#endif
#define _sbpp_server_ip_included

#define SBPP_SERVER_IP_LENGTH 16

stock bool SBPP_IsValidServerIpOverride(const char[] ip)
{
if (ip[0] == '\0')
{
return true;
}

char octets[5][16];
if (ExplodeString(ip, ".", octets, sizeof(octets), sizeof(octets[])) != 4)
{
return false;
}

for (int octet = 0; octet < 4; octet++)
{
int length = strlen(octets[octet]);
if (length == 0 || length > 3)
{
return false;
}

for (int character = 0; character < length; character++)
{
if (!IsCharNumeric(octets[octet][character]))
{
return false;
}
}

if (StringToInt(octets[octet]) > 255)
{
return false;
}
}

return true;
}

stock void SBPP_ResolveServerIp(ConVar hostIp, const char[] configuredIp, char[] output, int maxLength)
{
if (configuredIp[0] != '\0')
{
strcopy(output, maxLength, configuredIp);
return;
}

int pieces[4];
int longIp = hostIp.IntValue;

pieces[0] = (longIp >> 24) & 0x000000FF;
pieces[1] = (longIp >> 16) & 0x000000FF;
pieces[2] = (longIp >> 8) & 0x000000FF;
pieces[3] = longIp & 0x000000FF;

FormatEx(output, maxLength, "%d.%d.%d.%d", pieces[0], pieces[1], pieces[2], pieces[3]);
}
41 changes: 28 additions & 13 deletions game/addons/sourcemod/scripting/sbpp_comms.sp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <sourcemod>
#include <basecomm>
#include <sourcecomms>
#include <sbpp_server_ip>

#undef REQUIRE_PLUGIN
#include <adminmenu>
Expand Down Expand Up @@ -95,7 +96,8 @@ Database g_hDatabase;
Database SQLiteDB;

char
ServerIp[24]
ServerIp[SBPP_SERVER_IP_LENGTH]
, ConfiguredServerIp[SBPP_SERVER_IP_LENGTH]
, ServerPort[7]
, DatabasePrefix[10] = "sb"
#if defined LOG_QUERIES
Expand Down Expand Up @@ -230,11 +232,10 @@ public void OnPluginStart()
SetFailState("Database failure: could not find database config: %s", DATABASE);
return;
}
ReadConfig();
DB_Connect();
InitializeBackupDB();

ServerInfo();

if (g_bLate)
{
for (int client = 1; client <= MaxClients; client++)
Expand Down Expand Up @@ -2019,6 +2020,22 @@ public SMCResult ReadConfig_KeyValue(SMCParser smc, const char[] key, const char
DatabasePrefix = "sb";
}
}
else if (strcmp("ServerIP", key, false) == 0)
{
char configuredIp[64];
strcopy(configuredIp, sizeof(configuredIp), value);
TrimString(configuredIp);

if (SBPP_IsValidServerIpOverride(configuredIp))
{
strcopy(ConfiguredServerIp, sizeof(ConfiguredServerIp), configuredIp);
}
else
{
ConfiguredServerIp[0] = '\0';
LogError("Ignoring invalid ServerIP override; expected an IPv4 address");
}
}
else if (strcmp("RetryTime", key, false) == 0)
{
RetryTime = StringToFloat(value);
Expand All @@ -2036,10 +2053,10 @@ public SMCResult ReadConfig_KeyValue(SMCParser smc, const char[] key, const char
serverID = StringToInt(value);

// get our sb_id value if we have one
int sbid = GetConVarInt(FindConVar("sb_id"));
if (sbid != -1)
ConVar sbId = FindConVar("sb_id");
if (sbId != null && sbId.IntValue != -1)
{
serverID = sbid;
serverID = sbId.IntValue;
}

// if it's not valid, make it 0
Expand Down Expand Up @@ -2798,13 +2815,7 @@ stock void InsertTempBlock(int length, int type, const char[] name, const char[]

stock void ServerInfo()
{
int pieces[4];
int longip = CvarHostIp.IntValue;
pieces[0] = (longip >> 24) & 0x000000FF;
pieces[1] = (longip >> 16) & 0x000000FF;
pieces[2] = (longip >> 8) & 0x000000FF;
pieces[3] = longip & 0x000000FF;
FormatEx(ServerIp, sizeof(ServerIp), "%d.%d.%d.%d", pieces[0], pieces[1], pieces[2], pieces[3]);
SBPP_ResolveServerIp(CvarHostIp, ConfiguredServerIp, ServerIp, sizeof(ServerIp));
CvarPort.GetString(ServerPort, sizeof(ServerPort));
}

Expand All @@ -2817,6 +2828,8 @@ stock void ReadConfig()
return;
}

ConfiguredServerIp[0] = '\0';

char ConfigFile1[PLATFORM_MAX_PATH], ConfigFile2[PLATFORM_MAX_PATH];
BuildPath(Path_SM, ConfigFile1, sizeof(ConfigFile1), "configs/sourcebans/sourcebans.cfg");
BuildPath(Path_SM, ConfigFile2, sizeof(ConfigFile2), "configs/sourcebans/sourcecomms.cfg");
Expand Down Expand Up @@ -2858,6 +2871,8 @@ stock void ReadConfig()
PrintToServer("Loaded DefaultTime value: %d", DefaultTime);
PrintToServer("Loaded DisableUnblockImmunityCheck value: %d", DisUBImCheck);
#endif

ServerInfo();
}


Expand Down
Loading
Loading