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