]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/snmp-agent.cc
dnsdist: Fix DNS over plain HTTP broken by `reloadAllCertificates()`
[thirdparty/pdns.git] / pdns / snmp-agent.cc
CommitLineData
9f4eb5cc
RG
1#include "snmp-agent.hh"
2#include "misc.hh"
519f5484 3#include "threadname.hh"
77c9bc9a 4#ifdef RECURSOR
c390b2da 5#include "logger.hh"
77c9bc9a
PL
6#else
7#include "dolog.hh"
8#endif
9f4eb5cc
RG
9
10#ifdef HAVE_NET_SNMP
11
0e663c3b
RG
12#ifndef HAVE_SNMP_SELECT_INFO2
13/* that's terrible, because it means we are going to have trouble with large
14 FD numbers at some point.. */
15# define netsnmp_large_fd_set fd_set
16# define snmp_read2 snmp_read
17# define snmp_select_info2 snmp_select_info
18# define netsnmp_large_fd_set_init(...)
19# define netsnmp_large_fd_set_cleanup(...)
20# define NETSNMP_LARGE_FD_SET FD_SET
21# define NETSNMP_LARGE_FD_CLR FD_CLR
22# define NETSNMP_LARGE_FD_ZERO FD_ZERO
23# define NETSNMP_LARGE_FD_ISSET FD_ISSET
24#else
25# include <net-snmp/library/large_fd_set.h>
26#endif
27
708b29ca 28const std::array<oid, 11> SNMPAgent::snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
9f4eb5cc
RG
29
30int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
31 uint64_t value)
32{
33 struct counter64 val64;
34 val64.high = value >> 32;
35 val64.low = value & 0xffffffff;
36 snmp_set_var_typed_value(request->requestvb,
37 ASN_COUNTER64,
38 &val64,
39 sizeof(val64));
40 return SNMP_ERR_NOERROR;
41}
42
790a6a60 43bool SNMPAgent::sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
9f4eb5cc
RG
44 netsnmp_variable_list* varList)
45{
790a6a60
RG
46 try {
47 auto obj = std::unique_ptr<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>(varList, snmp_free_varbind);
48 return sender.send(std::move(obj));
49 }
50 catch (...) {
9f4eb5cc
RG
51 return false;
52 }
9f4eb5cc
RG
53}
54
0e663c3b 55void SNMPAgent::handleTrapsEvent()
9f4eb5cc 56{
790a6a60
RG
57 try {
58 while (true) {
59 auto obj = d_receiver.receive(snmp_free_varbind);
60 if (!obj) {
61 break;
62 }
63 send_v2trap(obj->get());
9f4eb5cc
RG
64 }
65 }
790a6a60
RG
66 catch (const std::exception& e) {
67 }
9f4eb5cc 68}
0e663c3b
RG
69
70void SNMPAgent::handleSNMPQueryEvent(int fd)
71{
72 netsnmp_large_fd_set fdset;
73 netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
74 NETSNMP_LARGE_FD_ZERO(&fdset);
75 NETSNMP_LARGE_FD_SET(fd, &fdset);
76 snmp_read2(&fdset);
77}
78
8b428a6b 79void SNMPAgent::handleTrapsCB(int /* fd */, FDMultiplexer::funcparam_t& var)
0e663c3b
RG
80{
81 SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
82 if (!agent || !*agent)
83 throw std::runtime_error("Invalid value received in SNMP trap callback");
84
85 (*agent)->handleTrapsEvent();
86}
87
88void SNMPAgent::handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var)
89{
90 SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
91 if (!agent || !*agent)
92 throw std::runtime_error("Invalid value received in SNMP trap callback");
93
94 (*agent)->handleSNMPQueryEvent(fd);
95}
96
9f4eb5cc
RG
97#endif /* HAVE_NET_SNMP */
98
99void SNMPAgent::worker()
100{
101#ifdef HAVE_NET_SNMP
4226cfd0 102 FDMultiplexer* mplexer = FDMultiplexer::getMultiplexerSilent();
0e663c3b
RG
103 if (mplexer == nullptr) {
104 throw std::runtime_error("No FD multiplexer found for the SNMP agent!");
105 }
106
77c9bc9a 107#ifdef RECURSOR
9548a664 108 string threadName = "rec/snmp";
77c9bc9a
PL
109#else
110 string threadName = "dnsdist/SNMP";
111#endif
519f5484 112 setThreadName(threadName);
c390b2da 113
0e663c3b 114 int maxfd = 0;
9f4eb5cc 115 int block = 1;
0e663c3b 116 netsnmp_large_fd_set fdset;
9f4eb5cc 117 struct timeval timeout = { 0, 0 };
0e663c3b
RG
118 struct timeval now;
119
120 /* we want to be notified if a trap is waiting
121 to be sent */
790a6a60 122 mplexer->addReadFD(d_receiver.getDescriptor(), &handleTrapsCB, this);
9f4eb5cc
RG
123
124 while(true) {
0e663c3b
RG
125 netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
126 NETSNMP_LARGE_FD_ZERO(&fdset);
9f4eb5cc 127
0576fe19
RG
128 block = 1;
129 timeout = { 0, 0 };
0e663c3b 130 snmp_select_info2(&maxfd, &fdset, &timeout, &block);
9f4eb5cc 131
0e663c3b
RG
132 for (int fd = 0; fd < maxfd; fd++) {
133 if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
134 mplexer->addReadFD(fd, &handleSNMPQueryCB, this);
9f4eb5cc
RG
135 }
136 }
0e663c3b
RG
137
138 /* run updates now */
139 int res = mplexer->run(&now, (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000));
140
141 /* we handle timeouts here, the rest has already been handled by callbacks */
142 if (res == 0) {
9f4eb5cc 143 snmp_timeout();
0576fe19 144 run_alarms();
9f4eb5cc 145 }
0e663c3b
RG
146
147 for (int fd = 0; fd < maxfd; fd++) {
148 if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
149 try {
150 mplexer->removeReadFD(fd);
151 }
152 catch(const FDMultiplexerException& e) {
153 /* we might get an exception when removing a closed file descriptor,
154 just ignore it */
155 }
156 }
157 }
9f4eb5cc
RG
158 }
159#endif /* HAVE_NET_SNMP */
160}
161
aa87b287 162SNMPAgent::SNMPAgent([[maybe_unused]] const std::string& name, [[maybe_unused]] const std::string& daemonSocket)
9f4eb5cc
RG
163{
164#ifdef HAVE_NET_SNMP
165 netsnmp_enable_subagent();
166 snmp_disable_log();
ace226c3 167 if (!daemonSocket.empty()) {
9f4eb5cc
RG
168 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
169 NETSNMP_DS_AGENT_X_SOCKET,
ace226c3 170 daemonSocket.c_str());
9f4eb5cc
RG
171 }
172 /* no need to load any MIBS,
173 and it causes import errors if some modules are not present */
174 setenv("MIBS", "", 1);
175
176 init_agent(name.c_str());
0576fe19
RG
177
178 /* we use select() so don't use SIGALARM to handle alarms.
179 Note that we need to handle alarms for automatic reconnection
ace226c3 180 to the daemon to work.
0576fe19
RG
181 */
182 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
183 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG,
184 1);
185
9f4eb5cc
RG
186 init_snmp(name.c_str());
187
c1d76521 188 auto [sender, receiver] = pdns::channel::createObjectQueue<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>();
790a6a60
RG
189 d_sender = std::move(sender);
190 d_receiver = std::move(receiver);
9f4eb5cc
RG
191#endif /* HAVE_NET_SNMP */
192}