in ctsTraffic/ctsConfig.cpp [1079:1279]
static void ParseForAddress(vector<const wchar_t*>& args)
{
// -listen:<addr>
auto foundListen = begin(args);
while (foundListen != end(args))
{
foundListen = ranges::find_if(args, [](const wchar_t* parameter) -> bool {
const auto* const value = ParseArgument(parameter, L"-listen");
return value != nullptr;
});
if (foundListen != end(args))
{
// ReSharper disable once CppTooWideScopeInitStatement
const auto* const value = ParseArgument(*foundListen, L"-listen");
if (ctString::ctOrdinalEqualsCaseInsensative(L"*", value))
{
// add both v4 and v6
ctSockaddr listenAddr(AF_INET, ctSockaddr::AddressType::Any);
g_configSettings->ListenAddresses.push_back(listenAddr);
listenAddr.set(AF_INET6, ctSockaddr::AddressType::Any);
g_configSettings->ListenAddresses.push_back(listenAddr);
}
else
{
auto tempAddresses(ctSockaddr::ResolveName(value));
if (tempAddresses.empty())
{
throw invalid_argument("-listen value did not resolve to an IP address");
}
g_configSettings->ListenAddresses.insert(end(g_configSettings->ListenAddresses), begin(tempAddresses), end(tempAddresses));
}
// always remove the arg from our vector
args.erase(foundListen);
// found_listen is now invalidated since we just erased what it's pointing to
// - reset it to begin() since we know it's not end()
foundListen = args.begin();
}
}
// -target:<addr>
auto foundTarget = begin(args);
while (foundTarget != end(args))
{
foundTarget = ranges::find_if(args, [](const wchar_t* parameter) -> bool {
const auto* const value = ParseArgument(parameter, L"-target");
return value != nullptr;
});
if (foundTarget != end(args))
{
if (!g_configSettings->ListenAddresses.empty())
{
throw invalid_argument("cannot specify both -Listen and -Target");
}
const auto* const value = ParseArgument(*foundTarget, L"-target");
auto tempAddresses(ctSockaddr::ResolveName(value));
if (tempAddresses.empty())
{
throw invalid_argument("-target value did not resolve to an IP address");
}
g_configSettings->TargetAddresses.insert(end(g_configSettings->TargetAddresses), begin(tempAddresses), end(tempAddresses));
// always remove the arg from our vector
args.erase(foundTarget);
// found_target is now invalidated since we just erased what it's pointing to
// - reset it to begin() since we know it's not end()
foundTarget = args.begin();
}
}
// -bind:<addr>
auto foundBind = begin(args);
while (foundBind != end(args))
{
foundBind = ranges::find_if(args, [](const wchar_t* parameter) -> bool {
const auto* const value = ParseArgument(parameter, L"-bind");
return value != nullptr;
});
if (foundBind != end(args))
{
// ReSharper disable once CppTooWideScopeInitStatement
const auto* const value = ParseArgument(*foundBind, L"-bind");
// check for a comma-delimited list of IP Addresses
if (ctString::ctOrdinalEqualsCaseInsensative(L"*", value))
{
// add both v4 and v6
ctSockaddr bindAddr(AF_INET, ctSockaddr::AddressType::Any);
g_configSettings->BindAddresses.push_back(bindAddr);
bindAddr.set(AF_INET6, ctSockaddr::AddressType::Any);
g_configSettings->BindAddresses.push_back(bindAddr);
}
else
{
auto tempAddresses(ctSockaddr::ResolveName(value));
if (tempAddresses.empty())
{
throw invalid_argument("-bind value did not resolve to an IP address");
}
g_configSettings->BindAddresses.insert(end(g_configSettings->BindAddresses), begin(tempAddresses), end(tempAddresses));
}
// always remove the arg from our vector
args.erase(foundBind);
// found_bind is now invalidated since we just erased what it's pointing to
// - reset it to begin() since we know it's not end()
foundBind = args.begin();
}
}
if (!g_configSettings->ListenAddresses.empty() && !g_configSettings->TargetAddresses.empty())
{
throw invalid_argument("cannot specify both -target and -listen");
}
if (!g_configSettings->ListenAddresses.empty() && !g_configSettings->BindAddresses.empty())
{
throw invalid_argument("cannot specify both -bind and -listen");
}
if (g_configSettings->ListenAddresses.empty() && g_configSettings->TargetAddresses.empty())
{
throw invalid_argument("must specify either -target or -listen");
}
// default bind addresses if not listening and did not exclusively want to bind
if (g_configSettings->ListenAddresses.empty() && g_configSettings->BindAddresses.empty())
{
ctSockaddr defaultAddr(AF_INET, ctSockaddr::AddressType::Any);
g_configSettings->BindAddresses.push_back(defaultAddr);
defaultAddr.set(AF_INET6, ctSockaddr::AddressType::Any);
g_configSettings->BindAddresses.push_back(defaultAddr);
}
if (!g_configSettings->TargetAddresses.empty())
{
//
// guarantee that bindaddress and targetaddress families can match
// - can't allow a bind address to be chosen if there are no TargetAddresses with the same family
//
uint32_t bindV4 = 0;
uint32_t bindV6 = 0;
uint32_t targetV4 = 0;
uint32_t targetV6 = 0;
for (const auto& addr : g_configSettings->BindAddresses)
{
if (addr.family() == AF_INET)
{
++bindV4;
}
else
{
++bindV6;
}
}
for (const auto& addr : g_configSettings->TargetAddresses)
{
if (addr.family() == AF_INET)
{
++targetV4;
}
else
{
++targetV6;
}
}
//
// if either bind or target has zero of either family, remove those addrs from the other vector
//
if (0 == bindV4)
{
std::erase_if(
g_configSettings->TargetAddresses,
[](const ctSockaddr& addr) noexcept { return addr.family() == AF_INET; }
);
}
else if (0 == targetV4)
{
std::erase_if(
g_configSettings->BindAddresses,
[](const ctSockaddr& addr) noexcept { return addr.family() == AF_INET; }
);
}
if (0 == bindV6)
{
std::erase_if(
g_configSettings->TargetAddresses,
[](const ctSockaddr& addr) noexcept { return addr.family() == AF_INET6; }
);
}
else if (0 == targetV6)
{
std::erase_if(
g_configSettings->BindAddresses,
[](const ctSockaddr& addr) noexcept { return addr.family() == AF_INET6; }
);
}
//
// now if either are of size zero, the user specified addresses which didn't align
//
if (g_configSettings->BindAddresses.empty() || g_configSettings->TargetAddresses.empty())
{
throw invalid_argument("-bind addresses and target addresses must match families");
}
}
}