* `setACL({netmask, netmask})`: replace the ACL set with these netmasks. Use `setACL({})` to reset the list, meaning no one can use us
* `showACL()`: show our ACL set
* Network related:
- * `addLocal(netmask, [false])`: add to addresses we listen on. Second optional parameter sets TCP/IP or not.
- * `setLocal(netmask, [false])`: reset list of addresses we listen on to this address. Second optional parameter sets TCP/IP or not.
+ * `addLocal(netmask, [false], [false])`: add to addresses we listen on. Second optional parameter sets TCP/IP or not. Third optional parameter sets SO_REUSEPORT when available.
+ * `setLocal(netmask, [false], [false])`: reset list of addresses we listen on to this address. Second optional parameter sets TCP/IP or not. Third optional parameter sets SO_REUSEPORT when available.
* Blocking related:
* `addDomainBlock(domain)`: block queries within this domain
* Carbon/Graphite/Metronome statistics related:
* `setMaxUDPOutstanding(n)`: set the maximum number of outstanding UDP queries to a given backend server. This can only be set at configuration time
* `setCacheCleaningDelay(n)`: set the interval in seconds between two runs of the cache cleaning algorithm, removing expired entries
* DNSCrypt related:
- * `addDNSCryptBind("127.0.0.1:8443", "provider name", "/path/to/resolver.cert", "/path/to/resolver.key"):` listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of "provider name", using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files
+ * `addDNSCryptBind("127.0.0.1:8443", "provider name", "/path/to/resolver.cert", "/path/to/resolver.key", [false]):` listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of "provider name", using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The last optional parameter sets SO_REUSEPORT when available
* `generateDNSCryptProviderKeys("/path/to/providerPublic.key", "/path/to/providerPrivate.key"):` generate a new provider keypair
* `generateDNSCryptCertificate("/path/to/providerPrivate.key", "/path/to/resolver.cert", "/path/to/resolver.key", serial, validFrom, validUntil):` generate a new resolver private key and related certificate, valid from the `validFrom` timestamp until the `validUntil` one, signed with the provider private key
* `printDNSCryptProviderFingerprint("/path/to/providerPublic.key")`: display the fingerprint of the provided resolver public key
g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
});
- g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<bool> doTCP) {
+ g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<bool> doTCP, boost::optional<bool> reusePort) {
setLuaSideEffect();
if(client)
return;
try {
ComboAddress loc(addr, 53);
g_locals.clear();
- g_locals.push_back({loc, doTCP ? *doTCP : true}); /// only works pre-startup, so no sync necessary
+ g_locals.push_back(std::make_tuple(loc, doTCP ? *doTCP : true, reusePort ? *reusePort : false)); /// only works pre-startup, so no sync necessary
}
catch(std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
}
});
- g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<bool> doTCP) {
+ g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<bool> doTCP, boost::optional<bool> reusePort) {
setLuaSideEffect();
if(client)
return;
}
try {
ComboAddress loc(addr, 53);
- g_locals.push_back({loc, doTCP ? *doTCP : true}); /// only works pre-startup, so no sync necessary
+ g_locals.push_back(std::make_tuple(loc, doTCP ? *doTCP : true, reusePort ? *reusePort : false)); /// only works pre-startup, so no sync necessary
}
catch(std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
}
});
- g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile) {
+ g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile, boost::optional<bool> reusePort) {
if (g_configurationDone) {
g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n";
return;
#ifdef HAVE_DNSCRYPT
try {
DnsCryptContext ctx(providerName, certFile, keyFile);
- g_dnsCryptLocals.push_back({ComboAddress(addr, 443), ctx});
+ g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort ? *reusePort : false));
}
catch(std::exception& e) {
errlog(e.what());
size_t idx = 0;
for (const auto& local : g_dnsCryptLocals) {
- const DnsCryptContext& ctx = local.second;
+ const DnsCryptContext& ctx = std::get<1>(local);
bool const hasOldCert = ctx.hadOldCertificate();
const DnsCryptCert& cert = ctx.getCurrentCertificate();
const DnsCryptCert& oldCert = ctx.getOldCertificate();
- ret<< (fmt % idx % local.first.toStringWithPort() % ctx.getProviderName() % cert.signedData.serial % DnsCryptContext::certificateDateToStr(cert.signedData.tsEnd) % (hasOldCert ? oldCert.signedData.serial : 0) % (hasOldCert ? DnsCryptContext::certificateDateToStr(oldCert.signedData.tsEnd) : "-")) << endl;
+ ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx.getProviderName() % cert.signedData.serial % DnsCryptContext::certificateDateToStr(cert.signedData.tsEnd) % (hasOldCert ? oldCert.signedData.serial : 0) % (hasOldCert ? DnsCryptContext::certificateDateToStr(oldCert.signedData.tsEnd) : "-")) << endl;
idx++;
}
string localaddresses;
for(const auto& loc : g_locals) {
if(!localaddresses.empty()) localaddresses += ", ";
- localaddresses += loc.first.toStringWithPort();
+ localaddresses += std::get<0>(loc).toStringWithPort();
}
Json my_json = Json::object {
GlobalStateHolder<NetmaskGroup> g_ACL;
string g_outputBuffer;
-vector<std::pair<ComboAddress, bool>> g_locals;
+vector<std::tuple<ComboAddress, bool, bool>> g_locals;
#ifdef HAVE_DNSCRYPT
-std::vector<std::pair<ComboAddress,DnsCryptContext>> g_dnsCryptLocals;
+std::vector<std::tuple<ComboAddress,DnsCryptContext,bool>> g_dnsCryptLocals;
#endif
vector<ClientState *> g_frontends;
GlobalStateHolder<pools_t> g_pools;
if(g_cmdLine.locals.size()) {
g_locals.clear();
for(auto loc : g_cmdLine.locals)
- g_locals.push_back({ComboAddress(loc, 53), true});
+ g_locals.push_back(std::make_tuple(ComboAddress(loc, 53), true, false));
}
if(g_locals.empty())
- g_locals.push_back({ComboAddress("127.0.0.1", 53), true});
+ g_locals.push_back(std::make_tuple(ComboAddress("127.0.0.1", 53), true, false));
g_configurationDone = true;
vector<ClientState*> toLaunch;
for(const auto& local : g_locals) {
ClientState* cs = new ClientState;
- cs->local= local.first;
+ cs->local= std::get<0>(local);
cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0);
if(cs->local.sin4.sin_family == AF_INET6) {
SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
}
//if(g_vm.count("bind-non-local"))
- bindAny(local.first.sin4.sin_family, cs->udpFD);
+ bindAny(cs->local.sin4.sin_family, cs->udpFD);
// if (!setSocketTimestamps(cs->udpFD))
// L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
- if(IsAnyAddress(local.first)) {
+ if(IsAnyAddress(cs->local)) {
int one=1;
setsockopt(cs->udpFD, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
#ifdef IPV6_RECVPKTINFO
setsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
#endif
}
+#ifdef SO_REUSEPORT
+ if (std::get<2>(local)) {
+ SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1);
+ }
+#endif
SBind(cs->udpFD, cs->local);
toLaunch.push_back(cs);
}
for(const auto& local : g_locals) {
- if(!local.second) { // no TCP/IP
- warnlog("Not providing TCP/IP service on local address '%s'", local.first.toStringWithPort());
+ if(!std::get<1>(local)) { // no TCP/IP
+ warnlog("Not providing TCP/IP service on local address '%s'", std::get<0>(local).toStringWithPort());
continue;
}
ClientState* cs = new ClientState;
- cs->local= local.first;
+ cs->local= std::get<0>(local);
cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
if(cs->local.sin4.sin_family == AF_INET6) {
SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
}
+#ifdef SO_REUSEPORT
+ if (std::get<2>(local)) {
+ SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
+ }
+#endif
// if(g_vm.count("bind-non-local"))
bindAny(cs->local.sin4.sin_family, cs->tcpFD);
SBind(cs->tcpFD, cs->local);
#ifdef HAVE_DNSCRYPT
for(auto& dcLocal : g_dnsCryptLocals) {
ClientState* cs = new ClientState;
- cs->local = dcLocal.first;
- cs->dnscryptCtx = &dcLocal.second;
+ cs->local = std::get<0>(dcLocal);
+ cs->dnscryptCtx = &(std::get<1>(dcLocal));
cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0);
if(cs->local.sin4.sin_family == AF_INET6) {
SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
g_frontends.push_back(cs);
cs = new ClientState;
- cs->local = dcLocal.first;
- cs->dnscryptCtx = &dcLocal.second;
+ cs->local = std::get<0>(dcLocal);
+ cs->dnscryptCtx = &(std::get<1>(dcLocal));
cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0);
SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1);
#ifdef TCP_DEFER_ACCEPT
SSetsockopt(cs->tcpFD, SOL_TCP,TCP_DEFER_ACCEPT, 1);
+#endif
+#ifdef SO_REUSEPORT
+ if (std::get<2>(dcLocal)) {
+ SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
+ }
#endif
if(cs->local.sin4.sin_family == AF_INET6) {
SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
extern ComboAddress g_serverControl; // not changed during runtime
-extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX)
+extern std::vector<std::tuple<ComboAddress, bool, bool>> g_locals; // not changed at runtime (we hope XXX)
extern vector<ClientState*> g_frontends;
extern std::string g_key; // in theory needs locking
extern bool g_truncateTC;
void resetLuaSideEffect(); // reset to indeterminate state
#ifdef HAVE_DNSCRYPT
-extern std::vector<std::pair<ComboAddress,DnsCryptContext>> g_dnsCryptLocals;
+extern std::vector<std::tuple<ComboAddress,DnsCryptContext,bool>> g_dnsCryptLocals;
int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr<DnsCryptQuery>& query, uint16_t* decryptedQueryLen, bool tcp, std::vector<uint8_t>& reponse);
#endif