]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Unify the management of DNS/DNSCrypt/DoT frontends 7694/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 9 Apr 2019 13:52:27 +0000 (15:52 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 9 Apr 2019 13:56:41 +0000 (15:56 +0200)
pdns/dnsdist-lua.cc
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/tcpiohandler.hh

index 69e5c571f67178cb8e6242c0d19a180e517382b9..a260593065c2becee748677f37880eb53d12f0b0 100644 (file)
@@ -497,10 +497,23 @@ void setupLuaConfig(bool client)
 
       try {
        ComboAddress loc(addr, 53);
-       g_locals.clear();
-       g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+        for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+          /* TLS and DNSCrypt frontends are separate */
+          if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+            it = g_frontends.erase(it);
+          }
+          else {
+            ++it;
+          }
+        }
+
+        // only works pre-startup, so no sync necessary
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        if (doTCP) {
+          g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        }
       }
-      catch(std::exception& e) {
+      catch(const std::exception& e) {
        g_outputBuffer="Error: "+string(e.what())+"\n";
       }
     });
@@ -523,7 +536,11 @@ void setupLuaConfig(bool client)
 
       try {
        ComboAddress loc(addr, 53);
-       g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+        // only works pre-startup, so no sync necessary
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        if (doTCP) {
+          g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        }
       }
       catch(std::exception& e) {
        g_outputBuffer="Error: "+string(e.what())+"\n";
@@ -1095,7 +1112,17 @@ void setupLuaConfig(bool client)
 
       try {
         auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
-        g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort, tcpFastOpenQueueSize, interface, cpus));
+
+        /* UDP */
+        auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
+        cs->dnscryptCtx = ctx;
+        g_dnsCryptLocals.push_back(ctx);
+        g_frontends.push_back(std::move(cs));
+
+        /* TCP */
+        cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+        cs->dnscryptCtx = ctx;
+        g_frontends.push_back(std::move(cs));
       }
       catch(std::exception& e) {
         errlog(e.what());
@@ -1115,9 +1142,9 @@ void setupLuaConfig(bool client)
       ret << (fmt % "#" % "Address" % "Provider Name") << endl;
       size_t idx = 0;
 
-      for (const auto& local : g_dnsCryptLocals) {
-        const std::shared_ptr<DNSCryptContext> ctx = std::get<1>(local);
-        ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx->getProviderName()) << endl;
+      for (const auto& frontend : g_frontends) {
+        const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
+        ret<< (fmt % idx % frontend->local.toStringWithPort() % ctx->getProviderName()) << endl;
         idx++;
       }
 
@@ -1132,7 +1159,7 @@ void setupLuaConfig(bool client)
 #ifdef HAVE_DNSCRYPT
       std::shared_ptr<DNSCryptContext> ret = nullptr;
       if (idx < g_dnsCryptLocals.size()) {
-        ret = std::get<1>(g_dnsCryptLocals.at(idx));
+        ret = g_dnsCryptLocals.at(idx);
       }
       return ret;
 #else
@@ -1285,7 +1312,7 @@ void setupLuaConfig(bool client)
       setLuaNoSideEffect();
       ClientState* ret = nullptr;
       if(num < g_frontends.size()) {
-        ret=g_frontends[num];
+        ret=g_frontends[num].get();
       }
       return ret;
       });
@@ -1633,9 +1660,16 @@ void setupLuaConfig(bool client)
           return;
         }
 
+        bool doTCP = true;
+        bool reusePort = false;
+        int tcpFastOpenQueueSize = 0;
+        std::string interface;
+        std::set<int> cpus;
+        (void) doTCP;
+
         if (vars) {
           bool doTCP = true;
-          parseLocalBindVars(vars, doTCP, frontend->d_reusePort, frontend->d_tcpFastOpenQueueSize, frontend->d_interface, frontend->d_cpus);
+          parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
           if (vars->count("provider")) {
             frontend->d_provider = boost::get<const string>((*vars)["provider"]);
@@ -1675,7 +1709,11 @@ void setupLuaConfig(bool client)
         try {
           frontend->d_addr = ComboAddress(addr, 853);
           vinfolog("Loading TLS provider %s", frontend->d_provider);
-          g_tlslocals.push_back(frontend); /// only works pre-startup, so no sync necessary
+          // only works pre-startup, so no sync necessary
+          auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+          cs->tlsFrontend = frontend;
+          g_tlslocals.push_back(cs->tlsFrontend);
+          g_frontends.push_back(std::move(cs));
         }
         catch(const std::exception& e) {
           g_outputBuffer="Error: "+string(e.what())+"\n";
index 291e16661d7cb1b7af40c158ca8fe53dc7f42552..704c575172a0533690e185b4ea777bc56f7c635d 100644 (file)
@@ -681,9 +681,14 @@ static void connectionThread(int sock, ComboAddress remote)
         acl+=s;
       }
       string localaddresses;
-      for(const auto& loc : g_locals) {
-        if(!localaddresses.empty()) localaddresses += ", ";
-        localaddresses += std::get<0>(loc).toStringWithPort();
+      for(const auto& front : g_frontends) {
+        if (front->tcp) {
+          continue;
+        }
+        if (!localaddresses.empty()) {
+          localaddresses += ", ";
+        }
+        localaddresses += front->local.toStringWithPort();
       }
 
       Json my_json = Json::object {
index 461c5f389649257d2ca3a08b69294b1b3bfcfd58..c5c03f6da1ecb18e7c6978c47381542382e05286 100644 (file)
@@ -92,14 +92,13 @@ bool g_allowEmptyResponse{false};
 GlobalStateHolder<NetmaskGroup> g_ACL;
 string g_outputBuffer;
 
-vector<std::tuple<ComboAddress, bool, bool, int, string, std::set<int>>> g_locals;
 std::vector<std::shared_ptr<TLSFrontend>> g_tlslocals;
-std::vector<std::tuple<ComboAddress,std::shared_ptr<DNSCryptContext>,bool, int, string, std::set<int> >> g_dnsCryptLocals;
+std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
 #ifdef HAVE_EBPF
 shared_ptr<BPFFilter> g_defaultBPFFilter;
 std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
 #endif /* HAVE_EBPF */
-vector<ClientState *> g_frontends;
+std::vector<std::unique_ptr<ClientState>> g_frontends;
 GlobalStateHolder<pools_t> g_pools;
 size_t g_udpVectorSize{1};
 
@@ -2168,6 +2167,102 @@ static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCoun
   }
 }
 
+static void setUpLocalBind(std::unique_ptr<ClientState>& cs)
+{
+  /* skip some warnings if there is an identical UDP context */
+  bool warn = cs->tcp == false || cs->tlsFrontend != nullptr;
+  int& fd = cs->tcp == false ? cs->udpFD : cs->tcpFD;
+  (void) warn;
+
+  fd = SSocket(cs->local.sin4.sin_family, cs->tcp == false ? SOCK_DGRAM : SOCK_STREAM, 0);
+
+  if (cs->tcp) {
+    SSetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1);
+#ifdef TCP_DEFER_ACCEPT
+    SSetsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
+#endif
+    if (cs->fastOpenQueueSize > 0) {
+#ifdef TCP_FASTOPEN
+      SSetsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, cs->fastOpenQueueSize);
+#else
+      if (warn) {
+        warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+      }
+#endif
+    }
+  }
+
+  if(cs->local.sin4.sin_family == AF_INET6) {
+    SSetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+  }
+
+  bindAny(cs->local.sin4.sin_family, fd);
+
+  if(!cs->tcp && IsAnyAddress(cs->local)) {
+    int one=1;
+    setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));     // linux supports this, so why not - might fail on other systems
+#ifdef IPV6_RECVPKTINFO
+    setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+#endif
+  }
+
+  if (cs->reuseport) {
+#ifdef SO_REUSEPORT
+    SSetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1);
+#else
+    if (warn) {
+      /* no need to warn again if configured but support is not available, we already did for UDP */
+      warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
+    }
+#endif
+  }
+
+  const std::string& itf = cs->interface;
+  if (!itf.empty()) {
+#ifdef SO_BINDTODEVICE
+    int res = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
+    if (res != 0) {
+      warnlog("Error setting up the interface on local address '%s': %s", cs->local.toStringWithPort(), strerror(errno));
+    }
+#else
+    if (warn) {
+      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", cs->local.toStringWithPort());
+    }
+#endif
+  }
+
+#ifdef HAVE_EBPF
+  if (g_defaultBPFFilter) {
+    cs->attachFilter(g_defaultBPFFilter);
+    vinfolog("Attaching default BPF Filter to %s frontend %s", (!cs->tcp ? "UDP" : "TCP"), cs->local.toStringWithPort());
+  }
+#endif /* HAVE_EBPF */
+
+  if (cs->tlsFrontend != nullptr) {
+    if (!cs->tlsFrontend->setupTLS()) {
+      errlog("Error while setting up TLS on local address '%s', exiting", cs->local.toStringWithPort());
+      _exit(EXIT_FAILURE);
+    }
+  }
+
+  SBind(fd, cs->local);
+
+  if (cs->tcp) {
+    SListen(cs->tcpFD, 64);
+    if (cs->tlsFrontend != nullptr) {
+      warnlog("Listening on %s for TLS", cs->local.toStringWithPort());
+    }
+    else if (cs->dnscryptCtx != nullptr) {
+      warnlog("Listening on %s for DNSCrypt", cs->local.toStringWithPort());
+    }
+    else {
+      warnlog("Listening on %s", cs->local.toStringWithPort());
+    }
+  }
+
+  cs->ready = true;
+}
+
 struct 
 {
   vector<string> locals;
@@ -2449,291 +2544,42 @@ try
     }
   }
 
-  if(g_cmdLine.locals.size()) {
-    g_locals.clear();
-    for(auto loc : g_cmdLine.locals)
-      g_locals.push_back(std::make_tuple(ComboAddress(loc, 53), true, false, 0, "", std::set<int>()));
-  }
-  
-  if(g_locals.empty())
-    g_locals.push_back(std::make_tuple(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>()));
-
-  g_configurationDone = true;
-
-  vector<ClientState*> toLaunch;
-  for(const auto& local : g_locals) {
-    ClientState* cs = new ClientState;
-    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(cs->local.sin4.sin_family, cs->udpFD);
-
-    //    if (!setSocketTimestamps(cs->udpFD))
-    //      g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
-
-
-    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
-    }
-
-    if (std::get<2>(local)) {
-#ifdef SO_REUSEPORT
-      SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
-      warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", std::get<0>(local).toStringWithPort());
-#endif
-    }
-
-    const std::string& itf = std::get<4>(local);
-    if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
-      int res = setsockopt(cs->udpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
-      if (res != 0) {
-        warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(local).toStringWithPort(), strerror(errno));
+  if (!g_cmdLine.locals.empty()) {
+    for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+      /* TLS and DNSCrypt frontends are separate */
+      if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+        it = g_frontends.erase(it);
       }
-#else
-      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(local).toStringWithPort());
-#endif
-    }
-
-#ifdef HAVE_EBPF
-    if (g_defaultBPFFilter) {
-      cs->attachFilter(g_defaultBPFFilter);
-      vinfolog("Attaching default BPF Filter to UDP frontend %s", cs->local.toStringWithPort());
-    }
-#endif /* HAVE_EBPF */
-
-    cs->cpus = std::get<5>(local);
-
-    SBind(cs->udpFD, cs->local);
-    toLaunch.push_back(cs);
-    g_frontends.push_back(cs);
-    udpBindsCount++;
-  }
-
-  for(const auto& local : g_locals) {
-    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= std::get<0>(local);
-
-    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, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
-    if (std::get<3>(local) > 0) {
-#ifdef TCP_FASTOPEN
-      SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, std::get<3>(local));
-#else
-      warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", std::get<0>(local).toStringWithPort());
-#endif
-    }
-    if(cs->local.sin4.sin_family == AF_INET6) {
-      SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
-    }
-#ifdef SO_REUSEPORT
-    /* no need to warn again if configured but support is not available, we already did for UDP */
-    if (std::get<2>(local)) {
-      SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-    }
-#endif
-
-    const std::string& itf = std::get<4>(local);
-    if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
-      int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
-      if (res != 0) {
-        warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(local).toStringWithPort(), strerror(errno));
+      else {
+        ++it;
       }
-#else
-      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(local).toStringWithPort());
-#endif
     }
 
-#ifdef HAVE_EBPF
-    if (g_defaultBPFFilter) {
-      cs->attachFilter(g_defaultBPFFilter);
-      vinfolog("Attaching default BPF Filter to TCP frontend %s", cs->local.toStringWithPort());
+    for(const auto& loc : g_cmdLine.locals) {
+      /* UDP */
+      g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {})));
+      /* TCP */
+      g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {})));
     }
-#endif /* HAVE_EBPF */
-
-    //    if(g_vm.count("bind-non-local"))
-      bindAny(cs->local.sin4.sin_family, cs->tcpFD);
-    SBind(cs->tcpFD, cs->local);
-    SListen(cs->tcpFD, 64);
-    warnlog("Listening on %s", cs->local.toStringWithPort());
-
-    toLaunch.push_back(cs);
-    g_frontends.push_back(cs);
-    tcpBindsCount++;
   }
 
-  for(auto& dcLocal : g_dnsCryptLocals) {
-    ClientState* cs = new ClientState;
-    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);
-    }
-    bindAny(cs->local.sin4.sin_family, cs->udpFD);
-    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
-    }
-    if (std::get<2>(dcLocal)) {
-#ifdef SO_REUSEPORT
-      SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
-      warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
-    }
-
-    const std::string& itf = std::get<4>(dcLocal);
-    if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
-      int res = setsockopt(cs->udpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
-      if (res != 0) {
-        warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(dcLocal).toStringWithPort(), strerror(errno));
-      }
-#else
-      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
-    }
-
-#ifdef HAVE_EBPF
-    if (g_defaultBPFFilter) {
-      cs->attachFilter(g_defaultBPFFilter);
-      vinfolog("Attaching default BPF Filter to UDP DNSCrypt frontend %s", cs->local.toStringWithPort());
-    }
-#endif /* HAVE_EBPF */
-    SBind(cs->udpFD, cs->local);    
-    toLaunch.push_back(cs);
-    g_frontends.push_back(cs);
-    udpBindsCount++;
-
-    cs = new ClientState;
-    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, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
-    if (std::get<3>(dcLocal) > 0) {
-#ifdef TCP_FASTOPEN
-      SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, std::get<3>(dcLocal));
-#else
-      warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
-    }
-
-#ifdef SO_REUSEPORT
-    /* no need to warn again if configured but support is not available, we already did for UDP */
-    if (std::get<2>(dcLocal)) {
-      SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-    }
-#endif
-
-    if (!itf.empty()) {
-#ifdef SO_BINDTODEVICE
-      int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
-      if (res != 0) {
-        warnlog("Error setting up the interface on local address '%s': %s", std::get<0>(dcLocal).toStringWithPort(), strerror(errno));
-      }
-#else
-      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", std::get<0>(dcLocal).toStringWithPort());
-#endif
-    }
-
-    if(cs->local.sin4.sin_family == AF_INET6) {
-      SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
-    }
-#ifdef HAVE_EBPF
-    if (g_defaultBPFFilter) {
-      cs->attachFilter(g_defaultBPFFilter);
-      vinfolog("Attaching default BPF Filter to TCP DNSCrypt frontend %s", cs->local.toStringWithPort());
-    }
-#endif /* HAVE_EBPF */
-
-    cs->cpus = std::get<5>(dcLocal);
-
-    bindAny(cs->local.sin4.sin_family, cs->tcpFD);
-    SBind(cs->tcpFD, cs->local);
-    SListen(cs->tcpFD, 64);
-    warnlog("Listening on %s", cs->local.toStringWithPort());
-    toLaunch.push_back(cs);
-    g_frontends.push_back(cs);
-    tcpBindsCount++;
+  if (g_frontends.empty()) {
+    /* UDP */
+    g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {})));
+    /* TCP */
+    g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {})));
   }
 
-  for(auto& frontend : g_tlslocals) {
-    ClientState* cs = new ClientState;
-    cs->local = frontend->d_addr;
-    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, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
-#endif
-    if (frontend->d_tcpFastOpenQueueSize > 0) {
-#ifdef TCP_FASTOPEN
-      SSetsockopt(cs->tcpFD, IPPROTO_TCP, TCP_FASTOPEN, frontend->d_tcpFastOpenQueueSize);
-#else
-      warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
-#endif
-    }
-    if (frontend->d_reusePort) {
-#ifdef SO_REUSEPORT
-      SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1);
-#else
-      warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", cs->local.toStringWithPort());
-#endif
-    }
-    if(cs->local.sin4.sin_family == AF_INET6) {
-      SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1);
-    }
-
-    if (!frontend->d_interface.empty()) {
-#ifdef SO_BINDTODEVICE
-      int res = setsockopt(cs->tcpFD, SOL_SOCKET, SO_BINDTODEVICE, frontend->d_interface.c_str(), frontend->d_interface.length());
-      if (res != 0) {
-        warnlog("Error setting up the interface on local address '%s': %s", cs->local.toStringWithPort(), strerror(errno));
-      }
-#else
-      warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", cs->local.toStringWithPort());
-#endif
-    }
+  g_configurationDone = true;
 
-    cs->cpus = frontend->d_cpus;
+  for(auto& frontend : g_frontends) {
+    setUpLocalBind(frontend);
 
-    bindAny(cs->local.sin4.sin_family, cs->tcpFD);
-    if (frontend->setupTLS()) {
-      cs->tlsFrontend = frontend;
-      SBind(cs->tcpFD, cs->local);
-      SListen(cs->tcpFD, 64);
-      warnlog("Listening on %s for TLS", cs->local.toStringWithPort());
-      toLaunch.push_back(cs);
-      g_frontends.push_back(cs);
-      tcpBindsCount++;
+    if (frontend->tcp == false) {
+      ++udpBindsCount;
     }
     else {
-      errlog("Error while setting up TLS on local address '%s', exiting", cs->local.toStringWithPort());
-      delete cs;
-      _exit(EXIT_FAILURE);
+      ++tcpBindsCount;
     }
   }
 
@@ -2831,16 +2677,16 @@ try
     }
   }
 
-  for(auto& cs : toLaunch) {
+  for(auto& cs : g_frontends) {
     if (cs->udpFD >= 0) {
-      thread t1(udpClientThread, cs);
+      thread t1(udpClientThread, cs.get());
       if (!cs->cpus.empty()) {
         mapThreadToCPUList(t1.native_handle(), cs->cpus);
       }
       t1.detach();
     }
     else if (cs->tcpFD >= 0) {
-      thread t1(tcpAcceptorThread, cs);
+      thread t1(tcpAcceptorThread, cs.get());
       if (!cs->cpus.empty()) {
         mapThreadToCPUList(t1.native_handle(), cs->cpus);
       }
index 663e18061bdb115b3deaef847b91d12ef1fa5d5e..8ffdaca2b44b4f96af00121c38fab4156b6d5606 100644 (file)
@@ -581,10 +581,15 @@ extern QueryCount g_qcount;
 
 struct ClientState
 {
+  ClientState(const ComboAddress& local_, bool isTCP, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_): cpus(cpus_), local(local_), interface(itfName), fastOpenQueueSize(fastOpenQueue), tcp(isTCP), reuseport(doReusePort)
+  {
+  }
+
   std::set<int> cpus;
   ComboAddress local;
   std::shared_ptr<DNSCryptContext> dnscryptCtx{nullptr};
-  shared_ptr<TLSFrontend> tlsFrontend;
+  std::shared_ptr<TLSFrontend> tlsFrontend{nullptr};
+  std::string interface;
   std::atomic<uint64_t> queries{0};
   std::atomic<uint64_t> tcpDiedReadingQuery{0};
   std::atomic<uint64_t> tcpDiedSendingResponse{0};
@@ -597,7 +602,11 @@ struct ClientState
   std::atomic<double> tcpAvgConnectionDuration{0.0};
   int udpFD{-1};
   int tcpFD{-1};
+  int fastOpenQueueSize{0};
   bool muted{false};
+  bool tcp;
+  bool reuseport;
+  bool ready{false};
 
   int getSocket() const
   {
@@ -1008,7 +1017,7 @@ extern ComboAddress g_serverControl; // not changed during runtime
 
 extern std::vector<std::tuple<ComboAddress, bool, bool, int, std::string, std::set<int>>> g_locals; // not changed at runtime (we hope XXX)
 extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
-extern vector<ClientState*> g_frontends;
+extern std::vector<std::unique_ptr<ClientState>> g_frontends;
 extern bool g_truncateTC;
 extern bool g_fixupCase;
 extern int g_tcpRecvTimeout;
@@ -1098,7 +1107,7 @@ bool processResponse(char** response, uint16_t* responseLen, size_t* responseSiz
 
 bool checkQueryHeaders(const struct dnsheader* dh);
 
-extern std::vector<std::tuple<ComboAddress, std::shared_ptr<DNSCryptContext>, bool, int, std::string, std::set<int> > > g_dnsCryptLocals;
+extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
 int handleDNSCryptQuery(char* packet, uint16_t len, std::shared_ptr<DNSCryptQuery> query, uint16_t* decryptedQueryLen, bool tcp, time_t now, std::vector<uint8_t>& response);
 boost::optional<std::vector<uint8_t>> checkDNSCryptQuery(const ClientState& cs, const char* query, uint16_t& len, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
 
index e14c535d859a24d3065ec6b937bf6f599f655383..5c2c90a0532b291c1be88488a8ba8c6d2fc650c8 100644 (file)
@@ -137,19 +137,15 @@ public:
     return res;
   }
 
-  std::set<int> d_cpus;
   std::vector<std::pair<std::string, std::string>> d_certKeyPairs;
   ComboAddress d_addr;
   std::string d_ciphers;
   std::string d_provider;
-  std::string d_interface;
   std::string d_ticketKeyFile;
 
   size_t d_maxStoredSessions{20480};
   time_t d_ticketsKeyRotationDelay{43200};
-  int d_tcpFastOpenQueueSize{0};
   uint8_t d_numberOfTicketsKeys{5};
-  bool d_reusePort{false};
   bool d_enableTickets{true};
 
 private: