#include "capabilities.hh"
#include "misc.hh"
-void dropCapabilities()
+void dropCapabilities(std::set<std::string> capabilitiesToKeep)
{
#ifdef HAVE_LIBCAP
cap_t caps = cap_get_proc();
if (caps != nullptr) {
cap_clear(caps);
+ if (!capabilitiesToKeep.empty()) {
+ std::vector<cap_value_t> toKeep;
+ toKeep.reserve(capabilitiesToKeep.size());
+
+ for (const auto& capToKeep : capabilitiesToKeep) {
+ cap_value_t value;
+ int res = cap_from_name(capToKeep.c_str(), &value);
+ if (res != 0) {
+ cap_free(caps);
+ throw std::runtime_error("Unable to convert capability name '" + capToKeep + "': " + stringerror());
+ }
+ toKeep.push_back(value);
+ }
+
+ if (cap_set_flag(caps, CAP_EFFECTIVE, toKeep.size(), toKeep.data(), CAP_SET) != 0) {
+ cap_free(caps);
+ throw std::runtime_error("Unable to set effective flag capabilities: " + stringerror());
+ }
+
+ if (cap_set_flag(caps, CAP_PERMITTED, toKeep.size(), toKeep.data(), CAP_SET) != 0) {
+ cap_free(caps);
+ throw std::runtime_error("Unable to set permitted flag capabilities: " + stringerror());
+ }
+ }
+
if (cap_set_proc(caps) != 0) {
cap_free(caps);
throw std::runtime_error("Unable to drop capabilities: " + stringerror());
sourceAddr = ComboAddress(source.substr(0, pos));
sourceItf = itfIdx;
}
+#ifdef SO_BINDTODEVICE
+ /* we need to retain CAP_NET_RAW to be able to set SO_BINDTODEVICE in the health checks */
+ g_capabilitiesToRetain.insert("CAP_NET_RAW");
+#endif
}
else
{
bool g_preserveTrailingData{false};
bool g_roundrobinFailOnNoServer{false};
+std::set<std::string> g_capabilitiesToRetain;
+
static void truncateTC(char* packet, uint16_t* len, size_t responseSize, unsigned int consumed)
try
{
or as an unprivileged user with ambient
capabilities like CAP_NET_BIND_SERVICE.
*/
- dropCapabilities();
+ dropCapabilities(g_capabilitiesToRetain);
}
catch(const std::exception& e) {
warnlog("%s", e.what());
extern DNSDistSNMPAgent* g_snmpAgent;
extern bool g_addEDNSToSelfGeneratedResponses;
+extern std::set<std::string> g_capabilitiesToRetain;
+
static const size_t s_udpIncomingBufferSize{1500};
enum class ProcessQueryResult { Drop, SendAnswer, PassToBackend };