]> git.ipfire.org Git - thirdparty/squid.git/blob - src/snmp_core.cc
Use ERR_ACCESS_DENIED for HTTP 403 (Forbidden) errors (#1899)
[thirdparty/squid.git] / src / snmp_core.cc
1 /*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 49 SNMP support */
10
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/AsyncCallbacks.h"
14 #include "base/CbcPointer.h"
15 #include "CachePeer.h"
16 #include "CachePeers.h"
17 #include "client_db.h"
18 #include "comm.h"
19 #include "comm/Connection.h"
20 #include "comm/Loops.h"
21 #include "fatal.h"
22 #include "ip/Address.h"
23 #include "ip/tools.h"
24 #include "ipc/StartListening.h"
25 #include "snmp/Forwarder.h"
26 #include "snmp_agent.h"
27 #include "snmp_core.h"
28 #include "SnmpRequest.h"
29 #include "SquidConfig.h"
30 #include "SquidMath.h"
31 #include "tools.h"
32
33 static void snmpPortOpened(Ipc::StartListeningAnswer&);
34
35 mib_tree_entry *mib_tree_head;
36 mib_tree_entry *mib_tree_last;
37
38 Comm::ConnectionPointer snmpIncomingConn;
39 Comm::ConnectionPointer snmpOutgoingConn;
40
41 static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType = atNone);
42 static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...);
43 static oid *snmpCreateOid(int length,...);
44 mib_tree_entry * snmpLookupNodeStr(mib_tree_entry *entry, const char *str);
45 bool snmpCreateOidFromStr(const char *str, oid **name, int *nl);
46 SQUIDCEXTERN void (*snmplib_debug_hook) (int, char *);
47 static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
48 static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
49 static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
50 static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn);
51 static void snmpDecodePacket(SnmpRequest * rq);
52 static void snmpConstructReponse(SnmpRequest * rq);
53
54 static oid_ParseFn *snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen);
55 static oid_ParseFn *snmpTreeGet(oid * Current, snint CurrentLen);
56 static mib_tree_entry *snmpTreeEntry(oid entry, snint len, mib_tree_entry * current);
57 static mib_tree_entry *snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current);
58 extern "C" void snmpSnmplibDebug(int lvl, char *buf);
59
60 /*
61 * The functions used during startup:
62 * snmpInit
63 * snmpConnectionOpen
64 * snmpConnectionClose
65 */
66
67 /*
68 * Turns the MIB into a Tree structure. Called during the startup process.
69 */
70 void
71 snmpInit(void)
72 {
73 debugs(49, 5, "snmpInit: Building SNMP mib tree structure");
74
75 snmplib_debug_hook = snmpSnmplibDebug;
76
77 /*
78 * This following bit of evil is to get the final node in the "squid" mib
79 * without having a "search" function. A search function should be written
80 * to make this and the other code much less evil.
81 */
82 mib_tree_head = snmpAddNode(snmpCreateOid(1, 1), 1, nullptr, nullptr, atNone, 0);
83
84 assert(mib_tree_head);
85 debugs(49, 5, "snmpInit: root is " << mib_tree_head);
86 snmpAddNodeStr("1", 3, nullptr, nullptr);
87
88 snmpAddNodeStr("1.3", 6, nullptr, nullptr);
89
90 snmpAddNodeStr("1.3.6", 1, nullptr, nullptr);
91 snmpAddNodeStr("1.3.6.1", 4, nullptr, nullptr);
92 snmpAddNodeStr("1.3.6.1.4", 1, nullptr, nullptr);
93 snmpAddNodeStr("1.3.6.1.4.1", 3495, nullptr, nullptr);
94 mib_tree_entry *m2 = snmpAddNodeStr("1.3.6.1.4.1.3495", 1, nullptr, nullptr);
95
96 mib_tree_entry *n = snmpLookupNodeStr(nullptr, "1.3.6.1.4.1.3495.1");
97 assert(m2 == n);
98
99 /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */
100 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, nullptr, nullptr);
101 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ, snmp_sysFn, static_Inst, atSum);
102 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR, snmp_sysFn, static_Inst, atSum);
103 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME, snmp_sysFn, static_Inst, atMax);
104
105 /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */
106 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, nullptr, nullptr);
107 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN, snmp_confFn, static_Inst);
108 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION, snmp_confFn, static_Inst);
109 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID, snmp_confFn, static_Inst);
110 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC, snmp_confFn, static_Inst);
111
112 /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */
113 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE, nullptr, nullptr);
114 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ, snmp_confFn, static_Inst, atSum);
115 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ, snmp_confFn, static_Inst, atSum);
116 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM, snmp_confFn, static_Inst, atMin);
117 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM, snmp_confFn, static_Inst, atMin);
118
119 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME, snmp_confFn, static_Inst);
120
121 /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */
122 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, nullptr, nullptr); /* SQ_PRF */
123
124 /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */
125 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS, nullptr, nullptr);
126 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF, snmp_prfSysFn, static_Inst, atSum);
127 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR, snmp_prfSysFn, static_Inst, atSum);
128 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE, snmp_prfSysFn, static_Inst, atSum);
129 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME, snmp_prfSysFn, static_Inst, atSum);
130 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE, snmp_prfSysFn, static_Inst, atSum);
131 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ, snmp_prfSysFn, static_Inst, atSum);
132 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT, snmp_prfSysFn, static_Inst, atSum);
133 /*
134 Amos comments:
135 The meaning of LRU is "oldest timestamped object in cache, if LRU algorithm is
136 used"...
137 What this SMP support needs to do is aggregate via a special filter equivalent to
138 min() to retain the semantic oldest-object meaning. A special one is needed that
139 works as unsigned and ignores '0' values.
140 */
141 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP, snmp_prfSysFn, static_Inst);
142 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ, snmp_prfSysFn, static_Inst, atSum);
143 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD, snmp_prfSysFn, static_Inst, atSum);
144 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD, snmp_prfSysFn, static_Inst, atSum);
145 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD, snmp_prfSysFn, static_Inst, atSum);
146 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD, snmp_prfSysFn, static_Inst, atMax);
147
148 /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */
149 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO, nullptr, nullptr);
150 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR, nullptr, nullptr);
151 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ, snmp_prfProtoFn, static_Inst, atSum);
152 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS, snmp_prfProtoFn, static_Inst, atSum);
153 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS, snmp_prfProtoFn, static_Inst, atSum);
154 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN, snmp_prfProtoFn, static_Inst, atSum);
155 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT, snmp_prfProtoFn, static_Inst, atSum);
156 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S, snmp_prfProtoFn, static_Inst, atSum);
157 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R, snmp_prfProtoFn, static_Inst, atSum);
158 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB, snmp_prfProtoFn, static_Inst, atSum);
159 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB, snmp_prfProtoFn, static_Inst, atSum);
160 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ, snmp_prfProtoFn, static_Inst, atSum);
161 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS, snmp_prfProtoFn, static_Inst, atSum);
162 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN, snmp_prfProtoFn, static_Inst, atSum);
163 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT, snmp_prfProtoFn, static_Inst, atSum);
164 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP, snmp_prfProtoFn, static_Inst, atSum);
165 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS, snmp_prfProtoFn, static_Inst, atSum);
166
167 /* Note this is time-series rather than 'static' */
168 /* cacheMedianSvcTable */
169 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN, nullptr, nullptr);
170
171 /* cacheMedianSvcEntry */
172 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, nullptr, nullptr);
173 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME, snmp_prfProtoFn, time_Inst, atAverage);
174 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL, snmp_prfProtoFn, time_Inst, atAverage);
175 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS, snmp_prfProtoFn, time_Inst, atAverage);
176 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM, snmp_prfProtoFn, time_Inst, atAverage);
177 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT, snmp_prfProtoFn, time_Inst, atAverage);
178 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY, snmp_prfProtoFn, time_Inst, atAverage);
179 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY, snmp_prfProtoFn, time_Inst, atAverage);
180 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS, snmp_prfProtoFn, time_Inst, atAverage);
181 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR, snmp_prfProtoFn, time_Inst, atAverage);
182 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR, snmp_prfProtoFn, time_Inst, atAverage);
183 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH, snmp_prfProtoFn, time_Inst, atAverage);
184
185 /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */
186 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, nullptr, nullptr);
187
188 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE, nullptr, nullptr);
189 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT, snmp_netIpFn, static_Inst, atSum);
190 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ, snmp_netIpFn, static_Inst, atSum);
191 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS, snmp_netIpFn, static_Inst, atSum);
192 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT, snmp_netIpFn, static_Inst, atSum);
193 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT, snmp_netIpFn, static_Inst, atSum);
194 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS, snmp_netIpFn, static_Inst, atSum);
195 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN, snmp_netIpFn, static_Inst, atSum);
196 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC, snmp_netIpFn, static_Inst, atSum);
197
198 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE, nullptr, nullptr);
199 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT, snmp_netFqdnFn, static_Inst, atSum);
200 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ, snmp_netFqdnFn, static_Inst, atSum);
201 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS, snmp_netFqdnFn, static_Inst, atSum);
202 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT, snmp_netFqdnFn, static_Inst, atSum);
203 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT, snmp_netFqdnFn, static_Inst, atSum);
204 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS, snmp_netFqdnFn, static_Inst, atSum);
205 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN, snmp_netFqdnFn, static_Inst, atSum);
206
207 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE, nullptr, nullptr);
208 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netDnsFn, static_Inst, atSum);
209 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netDnsFn, static_Inst, atSum);
210 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netDnsFn, static_Inst, atSum);
211
212 /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */
213 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, nullptr, nullptr);
214
215 /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */
216 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL, nullptr, nullptr);
217
218 /* CachePeerEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */
219 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, nullptr, nullptr);
220 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX, snmp_meshPtblFn, peer_Inst);
221 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME, snmp_meshPtblFn, peer_Inst);
222 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE, snmp_meshPtblFn, peer_Inst);
223 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR, snmp_meshPtblFn, peer_Inst);
224 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP, snmp_meshPtblFn, peer_Inst);
225 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP, snmp_meshPtblFn, peer_Inst);
226 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE, snmp_meshPtblFn, peer_Inst);
227 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE, snmp_meshPtblFn, peer_Inst);
228 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT, snmp_meshPtblFn, peer_Inst);
229 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED, snmp_meshPtblFn, peer_Inst);
230 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_FETCHES, snmp_meshPtblFn, peer_Inst);
231 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_RTT, snmp_meshPtblFn, peer_Inst);
232 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_IGN, snmp_meshPtblFn, peer_Inst);
233 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_S, snmp_meshPtblFn, peer_Inst);
234 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_R, snmp_meshPtblFn, peer_Inst);
235
236 /* cacheClientTable - 1.3.6.1.4.1.3495.1.5.2 */
237 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_CTBL, nullptr, nullptr);
238
239 /* BUG 2811: we NEED to create a reliable index for the client DB and make version 3 of the table. */
240 /* for now we have version 2 table with OID capable of mixed IPv4 / IPv6 clients and upgraded address text format. */
241
242 /* cacheClientEntry - 1.3.6.1.4.1.3495.1.5.2.2 */
243 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2", 2, nullptr, nullptr);
244 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR_TYPE, snmp_meshCtblFn, client_Inst);
245 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR, snmp_meshCtblFn, client_Inst);
246 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTREQ, snmp_meshCtblFn, client_Inst);
247 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTBYTES, snmp_meshCtblFn, client_Inst);
248 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITS, snmp_meshCtblFn, client_Inst);
249 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITBYTES, snmp_meshCtblFn, client_Inst);
250 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPREQ, snmp_meshCtblFn, client_Inst);
251 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPBYTES, snmp_meshCtblFn, client_Inst);
252 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITS, snmp_meshCtblFn, client_Inst);
253 mib_tree_last = snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITBYTES, snmp_meshCtblFn, client_Inst);
254
255 debugs(49, 9, "snmpInit: Completed SNMP mib tree structure");
256 }
257
258 void
259 snmpOpenPorts(void)
260 {
261 debugs(49, 5, "snmpConnectionOpen: Called");
262
263 if (Config.Port.snmp <= 0)
264 return;
265
266 snmpIncomingConn = new Comm::Connection;
267 snmpIncomingConn->local = Config.Addrs.snmp_incoming;
268 snmpIncomingConn->local.port(Config.Port.snmp);
269
270 if (!Ip::EnableIpv6 && !snmpIncomingConn->local.setIPv4()) {
271 debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpIncomingConn->local << " is not an IPv4 address.");
272 fatal("SNMP port cannot be opened.");
273 }
274 /* split-stack for now requires IPv4-only SNMP */
275 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpIncomingConn->local.isAnyAddr()) {
276 snmpIncomingConn->local.setIPv4();
277 }
278
279 auto call = asyncCallbackFun(49, 2, snmpPortOpened);
280 Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpIncomingConn, Ipc::fdnInSnmpSocket, call);
281
282 if (!Config.Addrs.snmp_outgoing.isNoAddr()) {
283 snmpOutgoingConn = new Comm::Connection;
284 snmpOutgoingConn->local = Config.Addrs.snmp_outgoing;
285 snmpOutgoingConn->local.port(Config.Port.snmp);
286
287 if (!Ip::EnableIpv6 && !snmpOutgoingConn->local.setIPv4()) {
288 debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpOutgoingConn->local << " is not an IPv4 address.");
289 fatal("SNMP port cannot be opened.");
290 }
291 /* split-stack for now requires IPv4-only SNMP */
292 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpOutgoingConn->local.isAnyAddr()) {
293 snmpOutgoingConn->local.setIPv4();
294 }
295 // TODO: Add/use snmpOutgoingPortOpened() instead of snmpPortOpened().
296 auto c = asyncCallbackFun(49, 2, snmpPortOpened);
297 Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpOutgoingConn, Ipc::fdnOutSnmpSocket, c);
298 } else {
299 snmpOutgoingConn = snmpIncomingConn;
300 debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local);
301 }
302 }
303
304 static void
305 snmpPortOpened(Ipc::StartListeningAnswer &answer)
306 {
307 const auto &conn = answer.conn;
308
309 if (!Comm::IsConnOpen(conn))
310 fatalf("Cannot open SNMP %s Port",(conn->fd == snmpIncomingConn->fd?"receiving":"sending"));
311
312 Comm::SetSelect(conn->fd, COMM_SELECT_READ, snmpHandleUdp, nullptr, 0);
313
314 if (conn->fd == snmpIncomingConn->fd)
315 debugs(1, DBG_IMPORTANT, "Accepting SNMP messages on " << snmpIncomingConn->local);
316 else if (conn->fd == snmpOutgoingConn->fd)
317 debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local);
318 else
319 fatalf("Lost SNMP port (%d) on FD %d", (int)conn->local.port(), conn->fd);
320 }
321
322 void
323 snmpClosePorts(void)
324 {
325 if (Comm::IsConnOpen(snmpIncomingConn)) {
326 debugs(49, DBG_IMPORTANT, "Closing SNMP receiving port " << snmpIncomingConn->local);
327 snmpIncomingConn->close();
328 }
329 snmpIncomingConn = nullptr;
330
331 if (Comm::IsConnOpen(snmpOutgoingConn) && snmpIncomingConn != snmpOutgoingConn) {
332 // Perform OUT port closure so as not to step on IN port when sharing a conn.
333 debugs(49, DBG_IMPORTANT, "Closing SNMP sending port " << snmpOutgoingConn->local);
334 snmpOutgoingConn->close();
335 }
336 snmpOutgoingConn = nullptr;
337 }
338
339 /*
340 * Functions for handling the requests.
341 */
342
343 /*
344 * Accept the UDP packet
345 */
346 void
347 snmpHandleUdp(int sock, void *)
348 {
349 static char buf[SNMP_REQUEST_SIZE];
350 Ip::Address from;
351 SnmpRequest *snmp_rq;
352 int len;
353
354 debugs(49, 5, "snmpHandleUdp: Called.");
355
356 Comm::SetSelect(sock, COMM_SELECT_READ, snmpHandleUdp, nullptr, 0);
357
358 memset(buf, '\0', sizeof(buf));
359
360 len = comm_udp_recvfrom(sock, buf, sizeof(buf)-1, 0, from);
361
362 if (len > 0) {
363 debugs(49, 3, "snmpHandleUdp: FD " << sock << ": received " << len << " bytes from " << from << ".");
364
365 snmp_rq = (SnmpRequest *)xcalloc(1, sizeof(SnmpRequest));
366 snmp_rq->buf = (u_char *) buf;
367 snmp_rq->len = len;
368 snmp_rq->sock = sock;
369 snmp_rq->outbuf = (unsigned char *)xmalloc(snmp_rq->outlen = SNMP_REQUEST_SIZE);
370 snmp_rq->from = from;
371 snmpDecodePacket(snmp_rq);
372 xfree(snmp_rq->outbuf);
373 xfree(snmp_rq);
374 } else {
375 int xerrno = errno;
376 debugs(49, DBG_IMPORTANT, "snmpHandleUdp: FD " << sock << " recvfrom: " << xstrerr(xerrno));
377 }
378 }
379
380 /*
381 * Turn SNMP packet into a PDU, check available ACL's
382 */
383 static void
384 snmpDecodePacket(SnmpRequest * rq)
385 {
386 struct snmp_pdu *PDU;
387 u_char *Community;
388 u_char *buf = rq->buf;
389 int len = rq->len;
390
391 if (!Config.accessList.snmp) {
392 debugs(49, DBG_IMPORTANT, "WARNING: snmp_access not configured. agent query DENIED from : " << rq->from);
393 return;
394 }
395
396 debugs(49, 5, "Called.");
397 PDU = snmp_pdu_create(0);
398 /* Always answer on SNMPv1 */
399 rq->session.Version = SNMP_VERSION_1;
400 Community = snmp_parse(&rq->session, PDU, buf, len);
401
402 /* Check if we have explicit permission to access SNMP data.
403 * default (set above) is to deny all */
404 if (Community) {
405 ACLFilledChecklist checklist(Config.accessList.snmp, nullptr);
406 checklist.src_addr = rq->from;
407 checklist.snmp_community = (char *) Community;
408
409 if (checklist.fastCheck().allowed() && (snmp_coexist_V2toV1(PDU))) {
410 rq->community = Community;
411 rq->PDU = PDU;
412 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]");
413 snmpConstructReponse(rq);
414 } else {
415 debugs(49, DBG_IMPORTANT, "WARNING: SNMP agent query DENIED from : " << rq->from);
416 snmp_free_pdu(PDU);
417 }
418 xfree(Community);
419
420 } else {
421 debugs(49, DBG_IMPORTANT, "WARNING: Failed SNMP agent query from : " << rq->from);
422 snmp_free_pdu(PDU);
423 }
424 }
425
426 /*
427 * Packet OK, ACL Check OK, Create response.
428 */
429 static void
430 snmpConstructReponse(SnmpRequest * rq)
431 {
432
433 struct snmp_pdu *RespPDU;
434
435 debugs(49, 5, "snmpConstructReponse: Called.");
436
437 if (UsingSmp() && IamWorkerProcess()) {
438 AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu&>(*rq->PDU),
439 static_cast<Snmp::Session&>(rq->session), rq->sock, rq->from));
440 snmp_free_pdu(rq->PDU);
441 return;
442 }
443
444 RespPDU = snmpAgentResponse(rq->PDU);
445 snmp_free_pdu(rq->PDU);
446
447 if (RespPDU != nullptr) {
448 snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen);
449 comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen);
450 snmp_free_pdu(RespPDU);
451 }
452 }
453
454 /*
455 * Decide how to respond to the request, construct a response and
456 * return the response to the requester.
457 */
458
459 struct snmp_pdu *
460 snmpAgentResponse(struct snmp_pdu *PDU) {
461
462 struct snmp_pdu *Answer = nullptr;
463
464 debugs(49, 5, "snmpAgentResponse: Called.");
465
466 if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) {
467 Answer->reqid = PDU->reqid;
468 Answer->errindex = 0;
469
470 if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) {
471 /* Indirect way */
472 int get_next = (PDU->command == SNMP_PDU_GETNEXT);
473 variable_list *VarPtr_;
474 variable_list **RespVars = &(Answer->variables);
475 oid_ParseFn *ParseFn;
476 int index = 0;
477 /* Loop through all variables */
478
479 for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) {
480 variable_list *VarPtr = VarPtr_;
481 variable_list *VarNew = nullptr;
482 oid *NextOidName = nullptr;
483 snint NextOidNameLen = 0;
484
485 ++index;
486
487 if (get_next)
488 ParseFn = snmpTreeNext(VarPtr->name, VarPtr->name_length, &NextOidName, &NextOidNameLen);
489 else
490 ParseFn = snmpTreeGet(VarPtr->name, VarPtr->name_length);
491
492 if (ParseFn == nullptr) {
493 Answer->errstat = SNMP_ERR_NOSUCHNAME;
494 debugs(49, 5, "snmpAgentResponse: No such oid. ");
495 } else {
496 if (get_next) {
497 VarPtr = snmp_var_new(NextOidName, NextOidNameLen);
498 xfree(NextOidName);
499 }
500
501 int * errstatTmp = &(Answer->errstat);
502
503 VarNew = (*ParseFn) (VarPtr, (snint *) errstatTmp);
504
505 if (get_next)
506 snmp_var_free(VarPtr);
507 }
508
509 if ((Answer->errstat != SNMP_ERR_NOERROR) || (VarNew == nullptr)) {
510 Answer->errindex = index;
511 debugs(49, 5, "snmpAgentResponse: error.");
512
513 if (VarNew)
514 snmp_var_free(VarNew);
515
516 while ((VarPtr = Answer->variables) != nullptr) {
517 Answer->variables = VarPtr->next_variable;
518 snmp_var_free(VarPtr);
519 }
520
521 /* Steal the original PDU list of variables for the error response */
522 Answer->variables = PDU->variables;
523
524 PDU->variables = nullptr;
525
526 return (Answer);
527 }
528
529 /* No error. Insert this var at the end, and move on to the next.
530 */
531 *RespVars = VarNew;
532
533 RespVars = &(VarNew->next_variable);
534 }
535 }
536 }
537
538 return (Answer);
539 }
540
541 static oid_ParseFn *
542 snmpTreeGet(oid * Current, snint CurrentLen)
543 {
544 oid_ParseFn *Fn = nullptr;
545 mib_tree_entry *mibTreeEntry = nullptr;
546 int count = 0;
547
548 debugs(49, 5, "snmpTreeGet: Called");
549
550 MemBuf tmp;
551 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current, CurrentLen, tmp) );
552
553 mibTreeEntry = mib_tree_head;
554
555 if (Current[count] == mibTreeEntry->name[count]) {
556 ++count;
557
558 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
559 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
560 ++count;
561 }
562 }
563
564 if (mibTreeEntry && mibTreeEntry->parsefunction)
565 Fn = mibTreeEntry->parsefunction;
566
567 debugs(49, 5, "snmpTreeGet: return");
568
569 return (Fn);
570 }
571
572 AggrType
573 snmpAggrType(oid* Current, snint CurrentLen)
574 {
575 debugs(49, 5, MYNAME);
576
577 mib_tree_entry* mibTreeEntry = mib_tree_head;
578 AggrType type = atNone;
579 int count = 0;
580
581 if (Current[count] == mibTreeEntry->name[count]) {
582 ++count;
583
584 while (mibTreeEntry != nullptr && count < CurrentLen) {
585 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
586 if (mibTreeEntry != nullptr)
587 type = mibTreeEntry->aggrType;
588 ++count;
589 }
590 }
591
592 return type;
593 }
594
595 static oid_ParseFn *
596 snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen)
597 {
598 oid_ParseFn *Fn = nullptr;
599 int count = 0;
600
601 debugs(49, 5, "snmpTreeNext: Called");
602
603 MemBuf tmp;
604 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp));
605
606 mib_tree_entry *mibTreeEntry = mib_tree_head;
607
608 if (mibTreeEntry && Current[count] == mibTreeEntry->name[count]) {
609 ++count;
610
611 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
612 mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
613
614 if (!nextmibTreeEntry)
615 break;
616 else
617 mibTreeEntry = nextmibTreeEntry;
618
619 ++count;
620 }
621 debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
622 } else {
623 return nullptr;
624 }
625
626 if (mibTreeEntry == mib_tree_last)
627 return (Fn);
628
629 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
630 *NextLen = CurrentLen;
631 *Next = (*mibTreeEntry->instancefunction) (Current, NextLen, mibTreeEntry, &Fn);
632 if (*Next) {
633 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
634 return (Fn);
635 }
636 }
637
638 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
639 --count;
640 mib_tree_entry *nextoid = snmpTreeSiblingEntry(Current[count], count, mibTreeEntry->parent);
641 if (nextoid) {
642 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid );
643 mibTreeEntry = nextoid;
644 ++count;
645 } else {
646 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
647
648 while (!nextoid) {
649 --count;
650
651 if (mibTreeEntry->parent->parent) {
652 nextoid = mibTreeEntry->parent;
653 mibTreeEntry = snmpTreeEntry(Current[count] + 1, count, nextoid->parent);
654
655 if (!mibTreeEntry) {
656 mibTreeEntry = nextoid;
657 nextoid = nullptr;
658 }
659 } else {
660 nextoid = mibTreeEntry;
661 mibTreeEntry = nullptr;
662 }
663 }
664 }
665 }
666 while ((mibTreeEntry) && (!mibTreeEntry->parsefunction)) {
667 mibTreeEntry = mibTreeEntry->leaves[0];
668 }
669
670 if (mibTreeEntry) {
671 *NextLen = mibTreeEntry->len;
672 *Next = (*mibTreeEntry->instancefunction) (mibTreeEntry->name, NextLen, mibTreeEntry, &Fn);
673 }
674
675 if (*Next) {
676 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
677 return (Fn);
678 } else
679 return nullptr;
680 }
681
682 static oid *
683 static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
684 {
685 oid *instance = nullptr;
686 if (*len <= current->len) {
687 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
688 memcpy(instance, name, sizeof(*name) * (*len));
689 instance[*len] = 0;
690 *len += 1;
691 }
692 *Fn = current->parsefunction;
693 return (instance);
694 }
695
696 static oid *
697 time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
698 {
699 oid *instance = nullptr;
700 int identifier = 0, loop = 0;
701 int index[TIME_INDEX_LEN] = {TIME_INDEX};
702
703 if (*len <= current->len) {
704 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
705 memcpy(instance, name, sizeof(*name) * (*len));
706 instance[*len] = *index;
707 *len += 1;
708 } else {
709 identifier = name[*len - 1];
710
711 while ((loop < TIME_INDEX_LEN) && (identifier != index[loop]))
712 ++loop;
713
714 if (loop < (TIME_INDEX_LEN - 1)) {
715 instance = (oid *)xmalloc(sizeof(*name) * (*len));
716 memcpy(instance, name, sizeof(*name) * (*len));
717 instance[*len - 1] = index[++loop];
718 }
719 }
720
721 *Fn = current->parsefunction;
722 return (instance);
723 }
724
725 static oid *
726 peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
727 {
728 oid *instance = nullptr;
729 const auto peersAvailable = CurrentCachePeers().size();
730
731 if (!peersAvailable) {
732 debugs(49, 6, "snmp peer_Inst: No Peers.");
733 current = current->parent->parent->parent->leaves[1];
734 while ((current) && (!current->parsefunction))
735 current = current->leaves[0];
736
737 if (!current)
738 return (instance);
739
740 instance = client_Inst(current->name, len, current, Fn);
741 } else if (*len <= current->len) {
742 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
743 instance = (oid *)xmalloc(sizeof(*name) * ( *len + 1));
744 memcpy(instance, name, sizeof(*name) * (*len));
745 instance[*len] = 1 ;
746 *len += 1;
747 } else {
748 int no = name[current->len] ;
749 int i;
750 // Note: This works because the Config.peers keeps its index according to its position.
751 for (i = 0; Less(i, peersAvailable) && Less(i, no); ++i);
752
753 if (Less(i, peersAvailable)) {
754 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i);
755 instance = (oid *)xmalloc(sizeof(*name) * (current->len + 1 ));
756 memcpy(instance, name, (sizeof(*name) * current->len ));
757 instance[current->len] = no + 1 ; // i.e. the next index on cache_peeer table.
758 } else {
759 debugs(49, 6, "snmp peer_Inst: We have " << i << " peers. Can't find #" << no);
760 return (instance);
761 }
762 }
763 *Fn = current->parsefunction;
764 return (instance);
765 }
766
767 static oid *
768 client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
769 {
770 oid *instance = nullptr;
771 Ip::Address laddr;
772 Ip::Address *aux;
773 int size = 0;
774 int newshift = 0;
775
776 if (*len <= current->len) {
777 aux = client_entry(nullptr);
778 if (aux)
779 laddr = *aux;
780 else
781 laddr.setAnyAddr();
782
783 if (laddr.isIPv4())
784 size = sizeof(in_addr);
785 else
786 size = sizeof(in6_addr);
787
788 debugs(49, 6, "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", size=" << size);
789
790 instance = (oid *)xmalloc(sizeof(*name) * (*len + size ));
791 memcpy(instance, name, (sizeof(*name) * (*len)));
792
793 if ( !laddr.isAnyAddr() ) {
794 addr2oid(laddr, &instance[ *len]); // the addr
795 *len += size ;
796 }
797 } else {
798 int shift = *len - current->len ; // i.e 4 or 16
799 oid2addr(&name[*len - shift], laddr,shift);
800 aux = client_entry(&laddr);
801 if (aux)
802 laddr = *aux;
803 else
804 laddr.setAnyAddr();
805
806 if (!laddr.isAnyAddr()) {
807 if (laddr.isIPv4())
808 newshift = sizeof(in_addr);
809 else
810 newshift = sizeof(in6_addr);
811
812 debugs(49, 6, "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", newshift=" << newshift);
813
814 instance = (oid *)xmalloc(sizeof(*name) * (current->len + newshift));
815 memcpy(instance, name, (sizeof(*name) * (current->len)));
816 addr2oid(laddr, &instance[current->len]); // the addr.
817 *len = current->len + newshift ;
818 }
819 }
820
821 *Fn = current->parsefunction;
822 return (instance);
823 }
824
825 /*
826 * Utility functions
827 */
828
829 /*
830 * Tree utility functions.
831 */
832
833 /*
834 * Returns a sibling object for the requested child object or NULL
835 * if it does not exit
836 */
837 static mib_tree_entry *
838 snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current)
839 {
840 mib_tree_entry *next = nullptr;
841 int count = 0;
842
843 while ((!next) && (count < current->children)) {
844 if (current->leaves[count]->name[len] == entry) {
845 next = current->leaves[count];
846 }
847
848 ++count;
849 }
850
851 /* Exactly the sibling on right */
852 if (count < current->children) {
853 next = current->leaves[count];
854 } else {
855 next = nullptr;
856 }
857
858 return (next);
859 }
860
861 /*
862 * Returns the requested child object or NULL if it does not exist
863 */
864 static mib_tree_entry *
865 snmpTreeEntry(oid entry, snint len, mib_tree_entry * current)
866 {
867 mib_tree_entry *next = nullptr;
868 int count = 0;
869
870 while ((!next) && current && (count < current->children)) {
871 if (current->leaves[count]->name[len] == entry) {
872 next = current->leaves[count];
873 }
874
875 ++count;
876 }
877
878 return (next);
879 }
880
881 static void
882 snmpAddNodeChild(mib_tree_entry *entry, mib_tree_entry *child)
883 {
884 debugs(49, 5, "snmpAddNodeChild: assigning " << child << " to parent " << entry);
885 entry->leaves = (mib_tree_entry **)xrealloc(entry->leaves, sizeof(mib_tree_entry *) * (entry->children + 1));
886 entry->leaves[entry->children] = child;
887 entry->leaves[entry->children]->parent = entry;
888 ++ entry->children;
889 }
890
891 mib_tree_entry *
892 snmpLookupNodeStr(mib_tree_entry *root, const char *str)
893 {
894 oid *name;
895 int namelen;
896 mib_tree_entry *e;
897
898 if (root)
899 e = root;
900 else
901 e = mib_tree_head;
902
903 if (! snmpCreateOidFromStr(str, &name, &namelen))
904 return nullptr;
905
906 /* I wish there were some kind of sensible existing tree traversal
907 * routine to use. I'll worry about that later */
908 if (namelen <= 1) {
909 xfree(name);
910 return e; /* XXX it should only be this? */
911 }
912
913 int i, r = 1;
914 while (r < namelen) {
915
916 /* Find the child node which matches this */
917 for (i = 0; i < e->children && e->leaves[i]->name[r] != name[r]; ++i) ; // seek-loop
918
919 /* Are we pointing to that node? */
920 if (i >= e->children)
921 break;
922 assert(e->leaves[i]->name[r] == name[r]);
923
924 /* Skip to that node! */
925 e = e->leaves[i];
926 ++r;
927 }
928
929 xfree(name);
930 return e;
931 }
932
933 bool
934 snmpCreateOidFromStr(const char *str, oid **name, int *nl)
935 {
936 char const *delim = ".";
937
938 *name = nullptr;
939 *nl = 0;
940 const char *s = str;
941
942 /* Parse the OID string into oid bits */
943 while (size_t len = strcspn(s, delim)) {
944 *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1));
945 (*name)[*nl] = atoi(s); // stops at the '.' delimiter
946 ++(*nl);
947 // exit with true when the last octet has been parsed
948 if (s[len] == '\0')
949 return true;
950 s += len+1;
951 }
952
953 // if we aborted before the lst octet was found, return false.
954 safe_free(*name);
955 return false;
956 }
957
958 /*
959 * Create an entry. Return a pointer to the newly created node, or NULL
960 * on failure.
961 */
962 static mib_tree_entry *
963 snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType)
964 {
965 mib_tree_entry *m, *b;
966 oid *n;
967 int nl;
968 char s[1024];
969
970 /* Find base node */
971 b = snmpLookupNodeStr(mib_tree_head, base_str);
972 if (! b)
973 return nullptr;
974 debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b);
975
976 /* Create OID string for new entry */
977 snprintf(s, 1024, "%s.%d", base_str, o);
978 if (! snmpCreateOidFromStr(s, &n, &nl))
979 return nullptr;
980
981 /* Create a node */
982 m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0);
983
984 /* Link it into the existing tree */
985 snmpAddNodeChild(b, m);
986
987 /* Return the node */
988 return m;
989 }
990
991 /*
992 * Adds a node to the MIB tree structure and adds the appropriate children
993 */
994 static mib_tree_entry *
995 snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...)
996 {
997 va_list args;
998 int loop;
999 mib_tree_entry *entry = nullptr;
1000 va_start(args, children);
1001
1002 MemBuf tmp;
1003 debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp));
1004
1005 va_start(args, children);
1006 entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry));
1007 entry->name = name;
1008 entry->len = len;
1009 entry->parsefunction = parsefunction;
1010 entry->instancefunction = instancefunction;
1011 entry->children = children;
1012 entry->leaves = nullptr;
1013 entry->aggrType = aggrType;
1014
1015 if (children > 0) {
1016 entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children);
1017
1018 for (loop = 0; loop < children; ++loop) {
1019 entry->leaves[loop] = va_arg(args, mib_tree_entry *);
1020 entry->leaves[loop]->parent = entry;
1021 }
1022 }
1023
1024 va_end(args);
1025 return (entry);
1026 }
1027 /* End of tree utility functions */
1028
1029 /*
1030 * Returns the list of parameters in an oid
1031 */
1032 static oid *
1033 snmpCreateOid(int length,...)
1034 {
1035 va_list args;
1036 oid *new_oid;
1037 int loop;
1038 va_start(args, length);
1039
1040 new_oid = (oid *)xmalloc(sizeof(oid) * length);
1041
1042 if (length > 0) {
1043 for (loop = 0; loop < length; ++loop) {
1044 new_oid[loop] = va_arg(args, int);
1045 }
1046 }
1047
1048 va_end(args);
1049 return (new_oid);
1050 }
1051
1052 /*
1053 * Debug calls, prints out the OID for debugging purposes.
1054 */
1055 const char *
1056 snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf)
1057 {
1058 char mbuf[16];
1059 int x;
1060 if (outbuf.isNull())
1061 outbuf.init(16, MAX_IPSTRLEN);
1062
1063 for (x = 0; x < Len; ++x) {
1064 size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
1065 outbuf.append(mbuf, bytes);
1066 }
1067 return outbuf.content();
1068 }
1069
1070 void
1071 snmpSnmplibDebug(int lvl, char *buf)
1072 {
1073 debugs(49, lvl, buf);
1074 }
1075
1076 /*
1077 IPv4 address: 10.10.0.9 ==>
1078 oid == 10.10.0.9
1079 IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1080 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
1081 */
1082 void
1083 addr2oid(Ip::Address &addr, oid * Dest)
1084 {
1085 u_int i ;
1086 u_char *cp = nullptr;
1087 struct in_addr i4addr;
1088 struct in6_addr i6addr;
1089 oid code = addr.isIPv6()? INETADDRESSTYPE_IPV6 : INETADDRESSTYPE_IPV4 ;
1090 u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr);
1091 // Dest[0] = code ;
1092 if ( code == INETADDRESSTYPE_IPV4 ) {
1093 addr.getInAddr(i4addr);
1094 cp = (u_char *) &(i4addr.s_addr);
1095 } else {
1096 addr.getInAddr(i6addr);
1097 cp = (u_char *) &i6addr;
1098 }
1099 for ( i=0 ; i < size ; ++i) {
1100 // OID's are in network order
1101 Dest[i] = *cp;
1102 ++cp;
1103 }
1104 MemBuf tmp;
1105 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp));
1106 }
1107
1108 /*
1109 oid == 10.10.0.9 ==>
1110 IPv4 address: 10.10.0.9
1111 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
1112 IPv6 address : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1113 */
1114 void
1115 oid2addr(oid * id, Ip::Address &addr, u_int size)
1116 {
1117 struct in_addr i4addr;
1118 struct in6_addr i6addr;
1119 u_int i;
1120 u_char *cp;
1121 if ( size == sizeof(struct in_addr) )
1122 cp = (u_char *) &(i4addr.s_addr);
1123 else
1124 cp = (u_char *) &(i6addr);
1125 MemBuf tmp;
1126 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) );
1127 for (i=0 ; i<size; ++i) {
1128 cp[i] = id[i];
1129 }
1130 if ( size == sizeof(struct in_addr) )
1131 addr = i4addr;
1132 else
1133 addr = i6addr;
1134 }
1135
1136 int
1137 Acl::SnmpCommunityCheck::match(ACLChecklist * const ch)
1138 {
1139 const auto checklist = Filled(ch);
1140
1141 return data->match (checklist->snmp_community);
1142 }
1143