]> granicus.if.org Git - pdns/commitdiff
start using sendfromto() for dnsdist for 0.0.0.0 service
authorbert hubert <bert.hubert@netherlabs.nl>
Tue, 10 Mar 2015 13:32:13 +0000 (14:32 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Tue, 10 Mar 2015 13:32:13 +0000 (14:32 +0100)
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/iputils.cc
pdns/iputils.hh
pdns/pdns_recursor.cc

index 943b2b4a8a6829061217423f62689b69cd389824..3782d04138311df9b4fa11b89045cd06b82c0444 100644 (file)
@@ -41,7 +41,6 @@
 
 /* Known sins:
    No centralized statistics
-   We neglect to do recvfromto() on 0.0.0.0
    Receiver is currently singlethreaded
       not *that* bad actually, but now that we are thread safe, might want to scale
    lack of help()
@@ -122,7 +121,11 @@ void* responderThread(std::shared_ptr<DownstreamState> state)
       --state->outstanding;  // you'd think an attacker could game this, but we're using connected socket
 
     dh->id = ids->origID;
-    sendto(ids->origFD, packet, len, 0, (struct sockaddr*)&ids->origRemote, ids->origRemote.getSocklen());
+    
+    if(ids->origDest.sin4.sin_family == 0)
+      sendto(ids->origFD, packet, len, 0, (struct sockaddr*)&ids->origRemote, ids->origRemote.getSocklen());
+    else
+      sendfromto(ids->origFD, packet, len, 0, ids->origDest, ids->origRemote);
     double udiff = ids->sentTime.udiff();
     vinfolog("Got answer from %s, relayed to %s, took %f usec", state->remote.toStringWithPort(), ids->origRemote.toStringWithPort(), udiff);
 
@@ -270,8 +273,6 @@ try
 {
   ComboAddress remote;
   remote.sin4.sin_family = cs->local.sin4.sin_family;
-  socklen_t socklen = cs->local.getSocklen();
-  
   char packet[1500];
   struct dnsheader* dh = (struct dnsheader*) packet;
   int len;
@@ -298,13 +299,20 @@ try
   auto localLimiters = g_limiters.getLocal();
   auto localPool = g_poolrules.getLocal();
   auto localMatchNodeFilter = g_suffixMatchNodeFilter.getLocal();
+
+  struct msghdr msgh;
+  struct iovec iov;
+  char cbuf[256];
+
+  remote.sin6.sin6_family=cs->local.sin6.sin6_family;
+  fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), packet, sizeof(packet), &remote);
+
   for(;;) {
     try {
-      len = recvfrom(cs->udpFD, packet, sizeof(packet), 0, (struct sockaddr*) &remote, &socklen);
+      len = recvmsg(cs->udpFD, &msgh, 0);
       if(len < (int)sizeof(struct dnsheader)) 
        continue;
 
-      
       if(!acl->match(remote))
        continue;
       
@@ -350,9 +358,14 @@ try
        g_regexBlocks++;
        continue;
       }
-      
+
       if(dh->qr) { // something turned it into a response
-       sendto(cs->udpFD, packet, len, 0, (struct sockaddr*)&remote, remote.getSocklen());
+       ComboAddress dest;
+       if(HarvestDestinationAddress(&msgh, &dest)) 
+         sendfromto(cs->udpFD, packet, len, 0, dest, remote);
+       else
+         sendto(cs->udpFD, packet, len, 0, (struct sockaddr*)&remote, remote.getSocklen());
+
        continue;
       }
 
@@ -399,6 +412,9 @@ try
       ids->sentTime.start();
       ids->qname = qname;
       ids->qtype = qtype;
+      ids->origDest.sin4.sin_family=0;
+      HarvestDestinationAddress(&msgh, &ids->origDest);
+      
       dh->id = idOffset;
       
       len = send(ss->fd, packet, len, 0);
@@ -1009,6 +1025,15 @@ try
     }
     if(g_vm.count("bind-non-local"))
       bindAny(local.sin4.sin_family, cs->udpFD);
+
+    //    setSocketTimestamps(cs->udpFD);
+
+    if(IsAnyAddress(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
+      setsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); 
+    }
+
     SBind(cs->udpFD, cs->local);    
     toLaunch.push_back(cs);
   }
index 4feb5909aa2de32a9342b95176d9bb5ea23e6bf0..b9776241cc69d1b43d3f74876136fd8eade044cf 100644 (file)
@@ -106,18 +106,20 @@ private:
 
 struct IDState
 {
-  IDState() : origFD(-1) {}
+  IDState() : origFD(-1) { origDest.sin4.sin_family = 0;}
   IDState(const IDState& orig)
   {
     origFD = orig.origFD;
     origID = orig.origID;
     origRemote = orig.origRemote;
+    origDest = orig.origDest;
     age.store(orig.age.load());
   }
 
   int origFD;  // set to <0 to indicate this state is empty   // 4
 
   ComboAddress origRemote;                                    // 28
+  ComboAddress origDest;                                      // 28
   StopWatch sentTime;                                         // 16
   DNSName qname;                                              // 80
   std::atomic<uint16_t> age;                                  // 4
index 5ea22f9790b65d25cdeb8f763dd42ab4572ba616..84ae98b7fe808ee8d80ae94033bb2c54dbe5a9d9 100644 (file)
@@ -115,7 +115,6 @@ bool IsAnyAddress(const ComboAddress& addr)
   return false;
 }
 
-// FIXME: this function is unused, and using it could reduce some code duplication
 int sendfromto(int sock, const char* data, int len, int flags, const ComboAddress& from, const ComboAddress& to)
 {
   struct msghdr msgh;
index 5b33f5dc166ed16ebfd0adf638d44ee50a2fe3ef..7586bcf81dae6d8fd458844da73d33a8076de4fc 100644 (file)
@@ -442,4 +442,5 @@ bool IsAnyAddress(const ComboAddress& addr);
 bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination);
 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
 void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
+int sendfromto(int sock, const char* data, int len, int flags, const ComboAddress& from, const ComboAddress& to);
 #endif
index 2401aa62d79d7b5ce0fb83a4baa15ce5b22422f4..1cde157f7e657c332e72e4e8279f534ec47b446a 100644 (file)
@@ -1188,7 +1188,6 @@ void makeUDPServerSockets()
       if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
        L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
       }
-
     }
 
     if( ::arg().mustDo("non-local-bind") )