• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.24
/pdns/dnsdistdist/dnsdist-xsk.cc
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#include "dnsdist.hh"
23
#include "dnsdist-xsk.hh"
24

25
#ifdef HAVE_XSK
26
#include <sys/poll.h>
27

28
#include "dolog.hh"
29
#include "dnsdist-metrics.hh"
30
#include "dnsdist-proxy-protocol.hh"
31
#include "threadname.hh"
32
#include "xsk.hh"
33

34
namespace dnsdist::xsk
35
{
36
std::vector<std::shared_ptr<XskSocket>> g_xsk;
37

38
void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<XskWorker> xskInfo)
39
{
×
40
  try {
×
41
    setThreadName("dnsdist/XskResp");
×
42
    auto pollfds = getPollFdsForWorker(*xskInfo);
×
43
    while (!dss->isStopped()) {
×
44
      poll(pollfds.data(), pollfds.size(), -1);
×
45
      bool needNotify = false;
×
46
      if ((pollfds[0].revents & POLLIN) != 0) {
×
47
        needNotify = true;
×
48
        xskInfo->cleanSocketNotification();
×
49
        xskInfo->processIncomingFrames([&](XskPacket& packet) {
×
50
          if (packet.getDataLen() < sizeof(dnsheader)) {
×
51
            xskInfo->markAsFree(packet);
×
52
            return;
×
53
          }
×
54
          const dnsheader_aligned dnsHeader(packet.getPayloadData());
×
55
          const auto queryId = dnsHeader->id;
×
56
          auto ids = dss->getState(queryId);
×
57
          if (ids) {
×
58
            if (!ids->isXSK()) {
×
59
              dss->restoreState(queryId, std::move(*ids));
×
60
              ids = std::nullopt;
×
61
            }
×
62
          }
×
63
          if (!ids) {
×
64
            xskInfo->markAsFree(packet);
×
65
            return;
×
66
          }
×
67
          auto response = packet.clonePacketBuffer();
×
68
          if (response.size() > packet.getCapacity()) {
×
69
            /* fallback to sending the packet via normal socket */
70
            ids->xskPacketHeader.clear();
×
71
          }
×
72
          if (!processResponderPacket(dss, response, std::move(*ids))) {
×
73
            xskInfo->markAsFree(packet);
×
74
            vinfolog("XSK packet dropped because processResponderPacket failed");
×
75
            return;
×
76
          }
×
77
          if (response.size() > packet.getCapacity()) {
×
78
            /* fallback to sending the packet via normal socket */
79
            sendUDPResponse(ids->cs->udpFD, response, ids->delayMsec, ids->hopLocal, ids->hopRemote);
×
80
            infolog("XSK packet falling back because packet is too large");
×
81
            xskInfo->markAsFree(packet);
×
82
            return;
×
83
          }
×
84
          packet.setHeader(ids->xskPacketHeader);
×
85
          if (!packet.setPayload(response)) {
×
86
            infolog("Unable to set XSK payload !");
×
87
          }
×
88
          if (ids->delayMsec > 0) {
×
89
            packet.addDelay(ids->delayMsec);
×
90
          }
×
91
          packet.updatePacket();
×
92
          xskInfo->pushToSendQueue(packet);
×
93
        });
×
94
      }
×
95
      if (needNotify) {
×
96
        xskInfo->notifyXskSocket();
×
97
      }
×
98
    }
×
99
  }
×
100
  catch (const std::exception& e) {
×
101
    errlog("XSK responder thread died because of exception: %s", e.what());
×
102
  }
×
103
  catch (const PDNSException& e) {
×
104
    errlog("XSK responder thread died because of PowerDNS exception: %s", e.reason);
×
105
  }
×
106
  catch (...) {
×
107
    errlog("XSK responder thread died because of an exception: %s", "unknown");
×
108
  }
×
109
}
×
110

111
bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, bool& expectProxyProtocol)
112
{
×
113
  const auto& from = packet.getFromAddr();
×
114
  expectProxyProtocol = expectProxyProtocolFrom(from);
×
115
  if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(from) && !expectProxyProtocol) {
×
116
    vinfolog("Query from %s dropped because of ACL", from.toStringWithPort());
×
117
    ++dnsdist::metrics::g_stats.aclDrops;
×
118
    return false;
×
119
  }
×
120
  clientState.queries++;
×
121
  ++dnsdist::metrics::g_stats.queries;
×
122

123
  return true;
×
124
}
×
125

126
void XskRouter(std::shared_ptr<XskSocket> xsk)
127
{
×
128
  setThreadName("dnsdist/XskRouter");
×
129
  uint32_t failed = 0;
×
130
  // packets to be submitted for sending
131
  vector<XskPacket> fillInTx;
×
132
  const auto& fds = xsk->getDescriptors();
×
133
  // list of workers that need to be notified
134
  std::set<int> needNotify;
×
135
  while (true) {
×
136
    try {
×
137
      auto ready = xsk->wait(-1);
×
138
      // descriptor 0 gets incoming AF_XDP packets
139
      if ((fds.at(0).revents & POLLIN) != 0) {
×
140
        auto packets = xsk->recv(64, &failed);
×
141
        dnsdist::metrics::g_stats.nonCompliantQueries += failed;
×
142
        for (auto& packet : packets) {
×
143
          const auto dest = packet.getToAddr();
×
144
          auto worker = xsk->getWorkerByDestination(dest);
×
145
          if (!worker) {
×
146
            xsk->markAsFree(packet);
×
147
            continue;
×
148
          }
×
149
          worker->pushToProcessingQueue(packet);
×
150
          needNotify.insert(worker->workerWaker.getHandle());
×
151
        }
×
152
        for (auto socket : needNotify) {
×
153
          uint64_t value = 1;
×
154
          auto written = write(socket, &value, sizeof(value));
×
155
          if (written != sizeof(value)) {
×
156
            // oh, well, the worker is clearly overloaded
157
            // but there is nothing we can do about it,
158
            // and hopefully the queue will be processed eventually
159
          }
×
160
        }
×
161
        needNotify.clear();
×
162
        ready--;
×
163
      }
×
164
      for (size_t fdIndex = 1; fdIndex < fds.size() && ready > 0; fdIndex++) {
×
165
        if ((fds.at(fdIndex).revents & POLLIN) != 0) {
×
166
          ready--;
×
167
          const auto& info = xsk->getWorkerByDescriptor(fds.at(fdIndex).fd);
×
168
          info->processOutgoingFrames([&](XskPacket& packet) {
×
169
            if ((packet.getFlags() & XskPacket::UPDATE) == 0) {
×
170
              xsk->markAsFree(packet);
×
171
              return;
×
172
            }
×
173
            if ((packet.getFlags() & XskPacket::DELAY) != 0) {
×
174
              xsk->pushDelayed(packet);
×
175
              return;
×
176
            }
×
177
            fillInTx.push_back(packet);
×
178
          });
×
179
          info->cleanWorkerNotification();
×
180
        }
×
181
      }
×
182
      xsk->pickUpReadyPacket(fillInTx);
×
183
      xsk->recycle(4096);
×
184
      xsk->fillFq();
×
185
      xsk->send(fillInTx);
×
186
    }
×
187
    catch (...) {
×
188
      vinfolog("Exception in XSK router loop");
×
189
    }
×
190
  }
×
191
}
×
192

193
void XskClientThread(ClientState* clientState)
194
{
×
195
  setThreadName("dnsdist/xskClient");
×
196
  auto xskInfo = clientState->xskInfo;
×
197

198
  for (;;) {
×
199
    while (!xskInfo->hasIncomingFrames()) {
×
200
      xskInfo->waitForXskSocket();
×
201
    }
×
202
    xskInfo->processIncomingFrames([&](XskPacket& packet) {
×
203
      if (XskProcessQuery(*clientState, packet)) {
×
204
        packet.updatePacket();
×
205
        xskInfo->pushToSendQueue(packet);
×
206
      }
×
207
      else {
×
208
        xskInfo->markAsFree(packet);
×
209
      }
×
210
    });
×
211
    xskInfo->notifyXskSocket();
×
212
  }
×
213
}
×
214

215
static std::string getDestinationMap(bool isV6)
216
{
649✔
217
  return !isV6 ? "/sys/fs/bpf/dnsdist/xsk-destinations-v4" : "/sys/fs/bpf/dnsdist/xsk-destinations-v6";
649!
218
}
649✔
219

220
void addDestinationAddress(const ComboAddress& addr)
221
{
×
222
  auto map = getDestinationMap(addr.isIPv6());
×
223
  XskSocket::addDestinationAddress(map, addr);
×
224
}
×
225

226
void removeDestinationAddress(const ComboAddress& addr)
227
{
×
228
  auto map = getDestinationMap(addr.isIPv6());
×
229
  XskSocket::removeDestinationAddress(map, addr);
×
230
}
×
231

232
void clearDestinationAddresses()
233
{
649✔
234
  auto map = getDestinationMap(false);
649✔
235
  XskSocket::clearDestinationMap(map, false);
649✔
236
  map = getDestinationMap(true);
649✔
237
  XskSocket::clearDestinationMap(map, true);
649✔
238
}
649✔
239

240
}
241
#endif /* HAVE_XSK */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc