1 #include "snmp-agent.hh"
3 #include "threadname.hh"
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
25 # include <net-snmp/library/large_fd_set.h>
28 const oid
SNMPAgent::snmpTrapOID
[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
29 const size_t SNMPAgent::snmpTrapOIDLen
= OID_LENGTH(SNMPAgent::snmpTrapOID
);
31 int SNMPAgent::setCounter64Value(netsnmp_request_info
* request
,
34 struct counter64 val64
;
35 val64
.high
= value
>> 32;
36 val64
.low
= value
& 0xffffffff;
37 snmp_set_var_typed_value(request
->requestvb
,
41 return SNMP_ERR_NOERROR
;
44 bool SNMPAgent::sendTrap(int fd
,
45 netsnmp_variable_list
* varList
)
47 ssize_t written
= write(fd
, &varList
, sizeof(varList
));
49 if (written
!= sizeof(varList
)) {
50 snmp_free_varbind(varList
);
56 void SNMPAgent::handleTrapsEvent()
58 netsnmp_variable_list
* varList
= nullptr;
62 got
= read(d_trapPipe
[0], &varList
, sizeof(varList
));
64 if (got
== sizeof(varList
)) {
66 snmp_free_varbind(varList
);
72 void SNMPAgent::handleSNMPQueryEvent(int fd
)
74 netsnmp_large_fd_set fdset
;
75 netsnmp_large_fd_set_init(&fdset
, FD_SETSIZE
);
76 NETSNMP_LARGE_FD_ZERO(&fdset
);
77 NETSNMP_LARGE_FD_SET(fd
, &fdset
);
81 void SNMPAgent::handleTrapsCB(int fd
, FDMultiplexer::funcparam_t
& var
)
83 SNMPAgent
** agent
= boost::any_cast
<SNMPAgent
*>(&var
);
84 if (!agent
|| !*agent
)
85 throw std::runtime_error("Invalid value received in SNMP trap callback");
87 (*agent
)->handleTrapsEvent();
90 void SNMPAgent::handleSNMPQueryCB(int fd
, FDMultiplexer::funcparam_t
& var
)
92 SNMPAgent
** agent
= boost::any_cast
<SNMPAgent
*>(&var
);
93 if (!agent
|| !*agent
)
94 throw std::runtime_error("Invalid value received in SNMP trap callback");
96 (*agent
)->handleSNMPQueryEvent(fd
);
99 #endif /* HAVE_NET_SNMP */
101 void SNMPAgent::worker()
104 FDMultiplexer
* mplexer
= FDMultiplexer::getMultiplexerSilent();
105 if (mplexer
== nullptr) {
106 throw std::runtime_error("No FD multiplexer found for the SNMP agent!");
110 string threadName
= "pdns-r/SNMP";
112 string threadName
= "dnsdist/SNMP";
114 setThreadName(threadName
);
118 netsnmp_large_fd_set fdset
;
119 struct timeval timeout
= { 0, 0 };
122 /* we want to be notified if a trap is waiting
124 mplexer
->addReadFD(d_trapPipe
[0], &handleTrapsCB
, this);
127 netsnmp_large_fd_set_init(&fdset
, FD_SETSIZE
);
128 NETSNMP_LARGE_FD_ZERO(&fdset
);
132 snmp_select_info2(&maxfd
, &fdset
, &timeout
, &block
);
134 for (int fd
= 0; fd
< maxfd
; fd
++) {
135 if (NETSNMP_LARGE_FD_ISSET(fd
, &fdset
)) {
136 mplexer
->addReadFD(fd
, &handleSNMPQueryCB
, this);
140 /* run updates now */
141 int res
= mplexer
->run(&now
, (timeout
.tv_sec
* 1000) + (timeout
.tv_usec
/ 1000));
143 /* we handle timeouts here, the rest has already been handled by callbacks */
149 for (int fd
= 0; fd
< maxfd
; fd
++) {
150 if (NETSNMP_LARGE_FD_ISSET(fd
, &fdset
)) {
152 mplexer
->removeReadFD(fd
);
154 catch(const FDMultiplexerException
& e
) {
155 /* we might get an exception when removing a closed file descriptor,
161 #endif /* HAVE_NET_SNMP */
164 SNMPAgent::SNMPAgent(const std::string
& name
, const std::string
& masterSocket
)
167 netsnmp_enable_subagent();
169 if (!masterSocket
.empty()) {
170 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID
,
171 NETSNMP_DS_AGENT_X_SOCKET
,
172 masterSocket
.c_str());
174 /* no need to load any MIBS,
175 and it causes import errors if some modules are not present */
176 setenv("MIBS", "", 1);
178 init_agent(name
.c_str());
180 /* we use select() so don't use SIGALARM to handle alarms.
181 Note that we need to handle alarms for automatic reconnection
182 to the master to work.
184 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID
,
185 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG
,
188 init_snmp(name
.c_str());
190 if (pipe(d_trapPipe
) < 0)
191 unixDie("Creating pipe");
193 if (!setNonBlocking(d_trapPipe
[0])) {
194 close(d_trapPipe
[0]);
195 close(d_trapPipe
[1]);
196 unixDie("Setting pipe non-blocking");
199 if (!setNonBlocking(d_trapPipe
[1])) {
200 close(d_trapPipe
[0]);
201 close(d_trapPipe
[1]);
202 unixDie("Setting pipe non-blocking");
205 #endif /* HAVE_NET_SNMP */