From: bert hubert Date: Tue, 10 Mar 2015 13:32:13 +0000 (+0100) Subject: start using sendfromto() for dnsdist for 0.0.0.0 service X-Git-Tag: dnsdist-1.0.0-alpha1~248^2~88^2~62 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=549d63c9fbddda52010eadd819247dfe7f413514;p=pdns start using sendfromto() for dnsdist for 0.0.0.0 service --- diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 943b2b4a8..3782d0413 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -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 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); } diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 4feb5909a..b9776241c 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -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 age; // 4 diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 5ea22f979..84ae98b7f 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -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; diff --git a/pdns/iputils.hh b/pdns/iputils.hh index 5b33f5dc1..7586bcf81 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -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 diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 2401aa62d..1cde157f7 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -1188,7 +1188,6 @@ void makeUDPServerSockets() if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) { L<