Skip to content
Open
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
14 changes: 14 additions & 0 deletions resources/stunserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ The following options are supported.
--primaryadvertised
--altadvertised
--configfile
--reuseaddr
--allow-response-address-unsafe
--help

Details of each option are as follows.
Expand Down Expand Up @@ -204,6 +206,18 @@ The --reuseaddr switch allows the STUN server port to be shared with other proce

____

**--allow-response-address-unsafe**

The --allow-response-address-unsafe switch enables support for the RFC 3489 RESPONSE-ADDRESS attribute. This attribute allows clients to specify a different IP address and port for receiving the STUN response, which is used for "Binding Lifetime Discovery" as described in RFC 3489.

**WARNING:** This option creates a security vulnerability as it allows the STUN server to be used as an amplification vector for denial-of-service (DoS) attacks. An attacker could send STUN requests with a spoofed source address and include a RESPONSE-ADDRESS attribute pointing to a victim's IP address, causing the server to send responses to the victim.

Only enable this option if you specifically need RFC 3489 compatibility for Binding Lifetime Discovery and understand the security implications.

This option is disabled by default.

____

**--help**

Prints this help page
Expand Down
1,461 changes: 745 additions & 716 deletions resources/stunserver.txtcode

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ struct StartupArgs
std::string strDosProtect;
std::string strConfigFile;
std::string strReuseAddr;
std::string strAllowResponseAddressUnsafe;

};

Expand All @@ -151,6 +152,7 @@ void DumpStartupArgs(StartupArgs& args)
PRINTARG(strMaxConnections);
PRINTARG(strDosProtect);
PRINTARG(strReuseAddr);
PRINTARG(strAllowResponseAddressUnsafe);
Logging::LogMsg(LL_DEBUG, "--------------------------\n");
}

Expand Down Expand Up @@ -513,6 +515,9 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
// ---- REUSE ADDRESS SWITCH -------------------------------------------
config.fReuseAddr = (argsIn.strReuseAddr.length() > 0);

// ---- ALLOW RESPONSE ADDRESS (UNSAFE) -------------------------------------------
config.fAllowResponseAddressUnsafe = (argsIn.strAllowResponseAddressUnsafe.length() > 0);

*pConfigOut = config;
hr = S_OK;

Expand Down Expand Up @@ -542,6 +547,7 @@ HRESULT ParseCommandLineArgs(int argc, char** argv, int startindex, StartupArgs*
cmdline.AddOption("ddp", no_argument, &pStartupArgs->strDosProtect);
cmdline.AddOption("configfile", required_argument, &pStartupArgs->strConfigFile);
cmdline.AddOption("reuseaddr", no_argument, &pStartupArgs->strReuseAddr);
cmdline.AddOption("allow-response-address-unsafe", no_argument, &pStartupArgs->strAllowResponseAddressUnsafe);

cmdline.ParseCommandLine(argc, argv, startindex, &fError);

Expand Down Expand Up @@ -598,6 +604,7 @@ HRESULT LoadConfigsFromFile(const std::string& filename, std::vector<StartupArgs
args.strMaxConnections = child.get("maxconn", "");
args.strDosProtect = child.get("ddp", "");
args.strReuseAddr = child.get("reuseaddr", "");
args.strAllowResponseAddressUnsafe = child.get("allow-response-address-unsafe", "");

configurations.push_back(args);
}
Expand Down
6 changes: 5 additions & 1 deletion server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ fMultiThreadedMode(false),
fTCP(false),
nMaxConnections(0), // zero means default
fEnableDosProtection(false),
fReuseAddr(false)
fReuseAddr(false),
fAllowResponseAddressUnsafe(false)
{
;
}
Expand Down Expand Up @@ -104,6 +105,9 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config)
// cleanup any thing that's going on now
Shutdown();

// set the fAllowResponseAddressUnsafe flag from config
tsa.fAllowResponseAddressUnsafe = config.fAllowResponseAddressUnsafe;

// optional code: create an authentication provider and initialize it here (if you want authentication)
// set the _spAuth member to reference it
// Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth));
Expand Down
2 changes: 2 additions & 0 deletions server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class CStunServerConfig

bool fReuseAddr; // if true, the socket option SO_REUSEADDR will be set

bool fAllowResponseAddressUnsafe; // if true, allow RFC3489 RESPONSE-ADDRESS attribute (security risk)

CStunServerConfig();
};

Expand Down
4 changes: 4 additions & 0 deletions server/tcpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,10 @@ HRESULT CTCPServer::Initialize(const CStunServerConfig& config)
// tsaHandler is sort of a hack for TCP. It's really just a glorified indication to the the
// CStunRequestHandler code to figure out if it can offer a CHANGED-ADDRESS attribute.

// set the fAllowResponseAddressUnsafe flag from config
tsaHandler.fAllowResponseAddressUnsafe = config.fAllowResponseAddressUnsafe;
tsaListenAll.fAllowResponseAddressUnsafe = config.fAllowResponseAddressUnsafe;

InitTSA(&tsaHandler, RolePP, config.fHasPP, config.addrPP, config.addrPrimaryAdvertised);
InitTSA(&tsaHandler, RolePA, config.fHasPA, config.addrPA, config.addrPrimaryAdvertised);
InitTSA(&tsaHandler, RoleAP, config.fHasAP, config.addrAP, config.addrAlternateAdvertised);
Expand Down
21 changes: 20 additions & 1 deletion stuncore/messagehandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ HRESULT CStunRequestHandler::ProcessRequestImpl()
CStunMessageReader &reader = *(_pMsgIn->pReader);

uint16_t responseport = 0;
CSocketAddress responseAddress;

// ignore anything that is not a request (with no response)
ChkIf(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL);
Expand All @@ -96,7 +97,25 @@ HRESULT CStunRequestHandler::ProcessRequestImpl()
reader.GetTransactionId(&_transid);
_fLegacyMode = reader.IsMessageLegacyFormat();

// we always try to honor the response port
// RFC 3489: Check for RESPONSE-ADDRESS attribute first (used for Binding Lifetime Discovery)
// This attribute allows the client to specify a different IP and port for receiving the response
// Only process this attribute if explicitly enabled (it's a security risk)
if (_pAddrSet->fAllowResponseAddressUnsafe && SUCCEEDED(reader.GetResponseAddress(&responseAddress)))
{
_fRequestHasResponsePort = true; // treat this similar to RESPONSE-PORT

if (_pMsgIn->fConnectionOriented)
{
// special case for TCP - we can't send response to a different address for connection oriented sockets
_error.errorcode = STUN_ERROR_BADREQUEST;
}
else
{
_pMsgOut->addrDest = responseAddress;
}
}

// we always try to honor the response port (RESPONSE-PORT takes precedence over RESPONSE-ADDRESS port)
reader.GetResponsePort(&responseport);
if (responseport != 0)
{
Expand Down
1 change: 1 addition & 0 deletions stuncore/messagehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct TransportAddress
struct TransportAddressSet
{
TransportAddress set[4]; // one for each socket role RolePP, RolePA, RoleAP, and RoleAA
bool fAllowResponseAddressUnsafe; // if true, allow RFC3489 RESPONSE-ADDRESS attribute (security risk)
};

struct StunErrorCode
Expand Down
10 changes: 10 additions & 0 deletions stuncore/stunreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,16 @@ HRESULT CStunMessageReader::GetResponseOriginAddress(CSocketAddress* pAddr)

}

HRESULT CStunMessageReader::GetResponseAddress(CSocketAddress* pAddr)
{
HRESULT hr = S_OK;

// RESPONSE-ADDRESS is an RFC 3489 attribute that allows the client to specify
// a different IP and port for receiving the response (used in Binding Lifetime Discovery)
hr = GetAddressHelper(STUN_ATTRIBUTE_RESPONSEADDRESS, pAddr);

return hr;
}

HRESULT CStunMessageReader::GetStringAttributeByType(uint16_t attributeType, char* pszValue, /*in-out*/ size_t size)
{
Expand Down
1 change: 1 addition & 0 deletions stuncore/stunreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class CStunMessageReader
HRESULT GetMappedAddress(CSocketAddress* pAddress);
HRESULT GetOtherAddress(CSocketAddress* pAddress);
HRESULT GetResponseOriginAddress(CSocketAddress* pAddress);
HRESULT GetResponseAddress(CSocketAddress* pAddress);

HRESULT GetStringAttributeByType(uint16_t attributeType, char* pszValue, /*in-out*/ size_t size);

Expand Down