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

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

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

86.84
/pdns/snmp-agent.cc
1
#include "snmp-agent.hh"
2
#include "misc.hh"
3
#include "threadname.hh"
4
#ifdef RECURSOR
5
#include "logger.hh"
6
#else
7
#include "dolog.hh"
8
#endif
9

10
#ifdef HAVE_NET_SNMP
11

12
#include <net-snmp/net-snmp-config.h>
13
#include <net-snmp/definitions.h>
14
#include <net-snmp/types.h>
15
#include <net-snmp/utilities.h>
16
#include <net-snmp/config_api.h>
17
#include <net-snmp/agent/net-snmp-agent-includes.h>
18
#undef INET6 /* SRSLY? */
19

20
#ifndef HAVE_SNMP_SELECT_INFO2
21
/* that's terrible, because it means we are going to have trouble with large
22
   FD numbers at some point.. */
23
# define netsnmp_large_fd_set fd_set
24
# define snmp_read2 snmp_read
25
# define snmp_select_info2 snmp_select_info
26
# define netsnmp_large_fd_set_init(...)
27
# define netsnmp_large_fd_set_cleanup(...)
28
# define NETSNMP_LARGE_FD_SET FD_SET
29
# define NETSNMP_LARGE_FD_CLR FD_CLR
30
# define NETSNMP_LARGE_FD_ZERO FD_ZERO
31
# define NETSNMP_LARGE_FD_ISSET FD_ISSET
32
#else
33
# include <net-snmp/library/large_fd_set.h>
34
#endif
35

36
static const std::array<oid, 11> s_snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
37

38
int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
39
                                 uint64_t value)
40
{
950✔
41
  struct counter64 val64;
950✔
42
  val64.high = value >> 32;
950✔
43
  val64.low = value & 0xffffffff;
950✔
44
  snmp_set_var_typed_value(request->requestvb,
950✔
45
                           ASN_COUNTER64,
950✔
46
                           &val64,
950✔
47
                           sizeof(val64));
950✔
48
  return SNMP_ERR_NOERROR;
950✔
49
}
950✔
50

51
void SNMPAgent::addSNMPTrapOID(netsnmp_variable_list** varList, const void* value, size_t len)
52
{
1✔
53
  snmp_varlist_add_variable(varList,
1✔
54
                            s_snmpTrapOID.data(),
1✔
55
                            s_snmpTrapOID.size(),
1✔
56
                            ASN_OBJECT_ID,
1✔
57
                            value,
1✔
58
                            len);
1✔
59
}
1✔
60

61
bool SNMPAgent::sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
62
                         netsnmp_variable_list* varList)
63
{
1✔
64
  try  {
1✔
65
    auto obj = std::unique_ptr<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>(varList, snmp_free_varbind);
1✔
66
    return sender.send(std::move(obj));
1✔
67
  }
1✔
68
  catch (...) {
1✔
69
    return false;
×
70
  }
×
71
}
1✔
72

73
void SNMPAgent::handleTrapsEvent()
74
{
1✔
75
  try {
1✔
76
    while (true) {
2✔
77
      auto obj = d_receiver.receive(snmp_free_varbind);
2✔
78
      if (!obj) {
2✔
79
        break;
1✔
80
      }
1✔
81
      send_v2trap(obj->get());
1✔
82
    }
1✔
83
  }
1✔
84
  catch (const std::exception& e) {
1✔
85
  }
×
86
}
1✔
87

88
void SNMPAgent::handleSNMPQueryEvent(int fd)
89
{
3,025✔
90
  netsnmp_large_fd_set fdset;
3,025✔
91
  netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
3,025✔
92
  NETSNMP_LARGE_FD_ZERO(&fdset);
3,025!
93
  NETSNMP_LARGE_FD_SET(fd, &fdset);
3,025✔
94
  snmp_read2(&fdset);
3,025✔
95
}
3,025✔
96

97
void SNMPAgent::handleTrapsCB(int /* fd */, FDMultiplexer::funcparam_t& var)
98
{
1✔
99
  SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
1✔
100
  if (!agent || !*agent)
1!
101
    throw std::runtime_error("Invalid value received in SNMP trap callback");
×
102

103
  (*agent)->handleTrapsEvent();
1✔
104
}
1✔
105

106
void SNMPAgent::handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var)
107
{
3,025✔
108
  SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
3,025✔
109
  if (!agent || !*agent)
3,025!
110
    throw std::runtime_error("Invalid value received in SNMP trap callback");
×
111

112
  (*agent)->handleSNMPQueryEvent(fd);
3,025✔
113
}
3,025✔
114

115
#endif /* HAVE_NET_SNMP */
116

117
void SNMPAgent::worker()
118
{
2✔
119
#ifdef HAVE_NET_SNMP
2✔
120
  FDMultiplexer* mplexer = FDMultiplexer::getMultiplexerSilent();
2✔
121
  if (mplexer == nullptr) {
2!
122
    throw std::runtime_error("No FD multiplexer found for the SNMP agent!");
×
123
  }
×
124

125
#ifdef RECURSOR
1✔
126
  string threadName = "rec/snmp";
1✔
127
#else
128
  string threadName = "dnsdist/SNMP";
1✔
129
#endif
1✔
130
  setThreadName(threadName);
2✔
131

132
  int maxfd = 0;
2✔
133
  int block = 1;
2✔
134
  netsnmp_large_fd_set fdset;
2✔
135
  struct timeval timeout = { 0, 0 };
2✔
136
  struct timeval now;
2✔
137

138
  /* we want to be notified if a trap is waiting
139
   to be sent */
140
  mplexer->addReadFD(d_receiver.getDescriptor(), &handleTrapsCB, this);
2✔
141

142
  while(true) {
3,031✔
143
    netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
3,029✔
144
    NETSNMP_LARGE_FD_ZERO(&fdset);
3,029!
145

146
    block = 1;
3,029✔
147
    timeout = { 0, 0 };
3,029✔
148
    snmp_select_info2(&maxfd, &fdset, &timeout, &block);
3,029✔
149

150
    for (int fd = 0; fd < maxfd; fd++) {
94,019✔
151
      if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
90,990✔
152
        mplexer->addReadFD(fd, &handleSNMPQueryCB, this);
9,087✔
153
      }
9,087✔
154
    }
90,990✔
155

156
    /* run updates now */
157
    int res = mplexer->run(&now, (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000));
3,029✔
158

159
    /* we handle timeouts here, the rest has already been handled by callbacks */
160
    if (res == 0) {
3,029✔
161
      snmp_timeout();
1✔
162
      run_alarms();
1✔
163
    }
1✔
164

165
    for (int fd = 0; fd < maxfd; fd++) {
93,965✔
166
      if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
90,936✔
167
        try {
9,081✔
168
          mplexer->removeReadFD(fd);
9,081✔
169
        }
9,081✔
170
        catch(const FDMultiplexerException& e) {
9,081✔
171
          /* we might get an exception when removing a closed file descriptor,
172
             just ignore it */
173
        }
×
174
      }
9,081✔
175
    }
90,936✔
176
  }
3,029✔
177
#endif /* HAVE_NET_SNMP */
2✔
178
}
2✔
179

180
SNMPAgent::SNMPAgent([[maybe_unused]] const std::string& name, [[maybe_unused]] const std::string& daemonSocket)
181
{
2✔
182
#ifdef HAVE_NET_SNMP
2✔
183
  netsnmp_enable_subagent();
2✔
184
  snmp_disable_log();
2✔
185
  if (!daemonSocket.empty()) {
2!
186
    netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
×
187
                          NETSNMP_DS_AGENT_X_SOCKET,
×
188
                          daemonSocket.c_str());
×
189
  }
×
190
  /* no need to load any MIBS,
191
     and it causes import errors if some modules are not present */
192
  setenv("MIBS", "", 1);
2✔
193

194
  init_agent(name.c_str());
2✔
195

196
  /* we use select() so don't use SIGALARM to handle alarms.
197
     Note that we need to handle alarms for automatic reconnection
198
     to the daemon to work.
199
  */
200
  netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
2✔
201
                         NETSNMP_DS_LIB_ALARM_DONT_USE_SIG,
2✔
202
                         1);
2✔
203

204
  init_snmp(name.c_str());
2✔
205

206
  auto [sender, receiver] = pdns::channel::createObjectQueue<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>();
2✔
207
  d_sender = std::move(sender);
2✔
208
  d_receiver = std::move(receiver);
2✔
209
#endif /* HAVE_NET_SNMP */
2✔
210
}
2✔
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