]> git.ipfire.org Git - thirdparty/squid.git/blob - src/snmp_core.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / snmp_core.cc
1 /*
2 * Copyright (C) 1996-2017 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 allow_t allow = ACCESS_DENIED;
387
388 if (!Config.accessList.snmp) {
389 debugs(49, DBG_IMPORTANT, "WARNING: snmp_access not configured. agent query DENIED from : " << rq->from);
390 return;
391 }
392
393 debugs(49, 5, HERE << "Called.");
394 PDU = snmp_pdu_create(0);
395 /* Allways answer on SNMPv1 */
396 rq->session.Version = SNMP_VERSION_1;
397 Community = snmp_parse(&rq->session, PDU, buf, len);
398
399 /* Check if we have explicit permission to access SNMP data.
400 * default (set above) is to deny all */
401 if (Community) {
402 ACLFilledChecklist checklist(Config.accessList.snmp, NULL, NULL);
403 checklist.src_addr = rq->from;
404 checklist.snmp_community = (char *) Community;
405 allow = checklist.fastCheck();
406
407 if (allow == ACCESS_ALLOWED && (snmp_coexist_V2toV1(PDU))) {
408 rq->community = Community;
409 rq->PDU = PDU;
410 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]");
411 snmpConstructReponse(rq);
412 } else {
413 debugs(49, DBG_IMPORTANT, "WARNING: SNMP agent query DENIED from : " << rq->from);
414 }
415 xfree(Community);
416
417 } else {
418 debugs(49, DBG_IMPORTANT, "WARNING: Failed SNMP agent query from : " << rq->from);
419 snmp_free_pdu(PDU);
420 }
421 }
422
423 /*
424 * Packet OK, ACL Check OK, Create reponse.
425 */
426 static void
427 snmpConstructReponse(SnmpRequest * rq)
428 {
429
430 struct snmp_pdu *RespPDU;
431
432 debugs(49, 5, "snmpConstructReponse: Called.");
433
434 if (UsingSmp() && IamWorkerProcess()) {
435 AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu&>(*rq->PDU),
436 static_cast<Snmp::Session&>(rq->session), rq->sock, rq->from));
437 snmp_free_pdu(rq->PDU);
438 return;
439 }
440
441 RespPDU = snmpAgentResponse(rq->PDU);
442 snmp_free_pdu(rq->PDU);
443
444 if (RespPDU != NULL) {
445 snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen);
446 comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen);
447 snmp_free_pdu(RespPDU);
448 }
449 }
450
451 /*
452 * Decide how to respond to the request, construct a response and
453 * return the response to the requester.
454 */
455
456 struct snmp_pdu *
457 snmpAgentResponse(struct snmp_pdu *PDU) {
458
459 struct snmp_pdu *Answer = NULL;
460
461 debugs(49, 5, "snmpAgentResponse: Called.");
462
463 if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) {
464 Answer->reqid = PDU->reqid;
465 Answer->errindex = 0;
466
467 if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) {
468 /* Indirect way */
469 int get_next = (PDU->command == SNMP_PDU_GETNEXT);
470 variable_list *VarPtr_;
471 variable_list **RespVars = &(Answer->variables);
472 oid_ParseFn *ParseFn;
473 int index = 0;
474 /* Loop through all variables */
475
476 for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) {
477 variable_list *VarPtr = VarPtr_;
478 variable_list *VarNew = NULL;
479 oid *NextOidName = NULL;
480 snint NextOidNameLen = 0;
481
482 ++index;
483
484 if (get_next)
485 ParseFn = snmpTreeNext(VarPtr->name, VarPtr->name_length, &NextOidName, &NextOidNameLen);
486 else
487 ParseFn = snmpTreeGet(VarPtr->name, VarPtr->name_length);
488
489 if (ParseFn == NULL) {
490 Answer->errstat = SNMP_ERR_NOSUCHNAME;
491 debugs(49, 5, "snmpAgentResponse: No such oid. ");
492 } else {
493 if (get_next) {
494 VarPtr = snmp_var_new(NextOidName, NextOidNameLen);
495 xfree(NextOidName);
496 }
497
498 int * errstatTmp = &(Answer->errstat);
499
500 VarNew = (*ParseFn) (VarPtr, (snint *) errstatTmp);
501
502 if (get_next)
503 snmp_var_free(VarPtr);
504 }
505
506 if ((Answer->errstat != SNMP_ERR_NOERROR) || (VarNew == NULL)) {
507 Answer->errindex = index;
508 debugs(49, 5, "snmpAgentResponse: error.");
509
510 if (VarNew)
511 snmp_var_free(VarNew);
512
513 while ((VarPtr = Answer->variables) != NULL) {
514 Answer->variables = VarPtr->next_variable;
515 snmp_var_free(VarPtr);
516 }
517
518 /* Steal the original PDU list of variables for the error response */
519 Answer->variables = PDU->variables;
520
521 PDU->variables = NULL;
522
523 return (Answer);
524 }
525
526 /* No error. Insert this var at the end, and move on to the next.
527 */
528 *RespVars = VarNew;
529
530 RespVars = &(VarNew->next_variable);
531 }
532 }
533 }
534
535 return (Answer);
536 }
537
538 static oid_ParseFn *
539 snmpTreeGet(oid * Current, snint CurrentLen)
540 {
541 oid_ParseFn *Fn = NULL;
542 mib_tree_entry *mibTreeEntry = NULL;
543 int count = 0;
544
545 debugs(49, 5, "snmpTreeGet: Called");
546
547 MemBuf tmp;
548 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current, CurrentLen, tmp) );
549
550 mibTreeEntry = mib_tree_head;
551
552 if (Current[count] == mibTreeEntry->name[count]) {
553 ++count;
554
555 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
556 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
557 ++count;
558 }
559 }
560
561 if (mibTreeEntry && mibTreeEntry->parsefunction)
562 Fn = mibTreeEntry->parsefunction;
563
564 debugs(49, 5, "snmpTreeGet: return");
565
566 return (Fn);
567 }
568
569 AggrType
570 snmpAggrType(oid* Current, snint CurrentLen)
571 {
572 debugs(49, 5, HERE);
573
574 mib_tree_entry* mibTreeEntry = mib_tree_head;
575 AggrType type = atNone;
576 int count = 0;
577
578 if (Current[count] == mibTreeEntry->name[count]) {
579 ++count;
580
581 while (mibTreeEntry != NULL && count < CurrentLen) {
582 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
583 if (mibTreeEntry != NULL)
584 type = mibTreeEntry->aggrType;
585 ++count;
586 }
587 }
588
589 return type;
590 }
591
592 static oid_ParseFn *
593 snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen)
594 {
595 oid_ParseFn *Fn = NULL;
596 int count = 0;
597
598 debugs(49, 5, "snmpTreeNext: Called");
599
600 MemBuf tmp;
601 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp));
602
603 mib_tree_entry *mibTreeEntry = mib_tree_head;
604
605 if (mibTreeEntry && Current[count] == mibTreeEntry->name[count]) {
606 ++count;
607
608 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
609 mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
610
611 if (!nextmibTreeEntry)
612 break;
613 else
614 mibTreeEntry = nextmibTreeEntry;
615
616 ++count;
617 }
618 debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
619 } else {
620 return NULL;
621 }
622
623 if (mibTreeEntry == mib_tree_last)
624 return (Fn);
625
626 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
627 *NextLen = CurrentLen;
628 *Next = (*mibTreeEntry->instancefunction) (Current, NextLen, mibTreeEntry, &Fn);
629 if (*Next) {
630 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
631 return (Fn);
632 }
633 }
634
635 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
636 --count;
637 mib_tree_entry *nextoid = snmpTreeSiblingEntry(Current[count], count, mibTreeEntry->parent);
638 if (nextoid) {
639 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid );
640 mibTreeEntry = nextoid;
641 ++count;
642 } else {
643 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
644
645 while (!nextoid) {
646 --count;
647
648 if (mibTreeEntry->parent->parent) {
649 nextoid = mibTreeEntry->parent;
650 mibTreeEntry = snmpTreeEntry(Current[count] + 1, count, nextoid->parent);
651
652 if (!mibTreeEntry) {
653 mibTreeEntry = nextoid;
654 nextoid = NULL;
655 }
656 } else {
657 nextoid = mibTreeEntry;
658 mibTreeEntry = NULL;
659 }
660 }
661 }
662 }
663 while ((mibTreeEntry) && (!mibTreeEntry->parsefunction)) {
664 mibTreeEntry = mibTreeEntry->leaves[0];
665 }
666
667 if (mibTreeEntry) {
668 *NextLen = mibTreeEntry->len;
669 *Next = (*mibTreeEntry->instancefunction) (mibTreeEntry->name, NextLen, mibTreeEntry, &Fn);
670 }
671
672 if (*Next) {
673 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
674 return (Fn);
675 } else
676 return NULL;
677 }
678
679 static oid *
680 static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
681 {
682 oid *instance = NULL;
683 if (*len <= current->len) {
684 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
685 memcpy(instance, name, sizeof(*name) * (*len));
686 instance[*len] = 0;
687 *len += 1;
688 }
689 *Fn = current->parsefunction;
690 return (instance);
691 }
692
693 static oid *
694 time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
695 {
696 oid *instance = NULL;
697 int identifier = 0, loop = 0;
698 int index[TIME_INDEX_LEN] = {TIME_INDEX};
699
700 if (*len <= current->len) {
701 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
702 memcpy(instance, name, sizeof(*name) * (*len));
703 instance[*len] = *index;
704 *len += 1;
705 } else {
706 identifier = name[*len - 1];
707
708 while ((loop < TIME_INDEX_LEN) && (identifier != index[loop]))
709 ++loop;
710
711 if (loop < (TIME_INDEX_LEN - 1)) {
712 instance = (oid *)xmalloc(sizeof(*name) * (*len));
713 memcpy(instance, name, sizeof(*name) * (*len));
714 instance[*len - 1] = index[++loop];
715 }
716 }
717
718 *Fn = current->parsefunction;
719 return (instance);
720 }
721
722 static oid *
723 peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
724 {
725 oid *instance = NULL;
726 CachePeer *peers = Config.peers;
727
728 if (peers == NULL) {
729 debugs(49, 6, "snmp peer_Inst: No Peers.");
730 current = current->parent->parent->parent->leaves[1];
731 while ((current) && (!current->parsefunction))
732 current = current->leaves[0];
733
734 if (!current)
735 return (instance);
736
737 instance = client_Inst(current->name, len, current, Fn);
738 } else if (*len <= current->len) {
739 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
740 instance = (oid *)xmalloc(sizeof(*name) * ( *len + 1));
741 memcpy(instance, name, sizeof(*name) * (*len));
742 instance[*len] = 1 ;
743 *len += 1;
744 } else {
745 int no = name[current->len] ;
746 int i;
747 // Note: This works because the Config.peers keeps its index according to its position.
748 for ( i=0 ; peers && (i < no) ; peers = peers->next , ++i ) ;
749
750 if (peers) {
751 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i);
752 instance = (oid *)xmalloc(sizeof(*name) * (current->len + 1 ));
753 memcpy(instance, name, (sizeof(*name) * current->len ));
754 instance[current->len] = no + 1 ; // i.e. the next index on cache_peeer table.
755 } else {
756 debugs(49, 6, "snmp peer_Inst: We have " << i << " peers. Can't find #" << no);
757 return (instance);
758 }
759 }
760 *Fn = current->parsefunction;
761 return (instance);
762 }
763
764 static oid *
765 client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
766 {
767 oid *instance = NULL;
768 Ip::Address laddr;
769 Ip::Address *aux;
770 int size = 0;
771 int newshift = 0;
772
773 if (*len <= current->len) {
774 aux = client_entry(NULL);
775 if (aux)
776 laddr = *aux;
777 else
778 laddr.setAnyAddr();
779
780 if (laddr.isIPv4())
781 size = sizeof(in_addr);
782 else
783 size = sizeof(in6_addr);
784
785 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", size=" << size);
786
787 instance = (oid *)xmalloc(sizeof(*name) * (*len + size ));
788 memcpy(instance, name, (sizeof(*name) * (*len)));
789
790 if ( !laddr.isAnyAddr() ) {
791 addr2oid(laddr, &instance[ *len]); // the addr
792 *len += size ;
793 }
794 } else {
795 int shift = *len - current->len ; // i.e 4 or 16
796 oid2addr(&name[*len - shift], laddr,shift);
797 aux = client_entry(&laddr);
798 if (aux)
799 laddr = *aux;
800 else
801 laddr.setAnyAddr();
802
803 if (!laddr.isAnyAddr()) {
804 if (laddr.isIPv4())
805 newshift = sizeof(in_addr);
806 else
807 newshift = sizeof(in6_addr);
808
809 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", newshift=" << newshift);
810
811 instance = (oid *)xmalloc(sizeof(*name) * (current->len + newshift));
812 memcpy(instance, name, (sizeof(*name) * (current->len)));
813 addr2oid(laddr, &instance[current->len]); // the addr.
814 *len = current->len + newshift ;
815 }
816 }
817
818 *Fn = current->parsefunction;
819 return (instance);
820 }
821
822 /*
823 * Utility functions
824 */
825
826 /*
827 * Tree utility functions.
828 */
829
830 /*
831 * Returns a sibling object for the requested child object or NULL
832 * if it does not exit
833 */
834 static mib_tree_entry *
835 snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current)
836 {
837 mib_tree_entry *next = NULL;
838 int count = 0;
839
840 while ((!next) && (count < current->children)) {
841 if (current->leaves[count]->name[len] == entry) {
842 next = current->leaves[count];
843 }
844
845 ++count;
846 }
847
848 /* Exactly the sibling on right */
849 if (count < current->children) {
850 next = current->leaves[count];
851 } else {
852 next = NULL;
853 }
854
855 return (next);
856 }
857
858 /*
859 * Returns the requested child object or NULL if it does not exist
860 */
861 static mib_tree_entry *
862 snmpTreeEntry(oid entry, snint len, mib_tree_entry * current)
863 {
864 mib_tree_entry *next = NULL;
865 int count = 0;
866
867 while ((!next) && current && (count < current->children)) {
868 if (current->leaves[count]->name[len] == entry) {
869 next = current->leaves[count];
870 }
871
872 ++count;
873 }
874
875 return (next);
876 }
877
878 void
879 snmpAddNodeChild(mib_tree_entry *entry, mib_tree_entry *child)
880 {
881 debugs(49, 5, "snmpAddNodeChild: assigning " << child << " to parent " << entry);
882 entry->leaves = (mib_tree_entry **)xrealloc(entry->leaves, sizeof(mib_tree_entry *) * (entry->children + 1));
883 entry->leaves[entry->children] = child;
884 entry->leaves[entry->children]->parent = entry;
885 ++ entry->children;
886 }
887
888 mib_tree_entry *
889 snmpLookupNodeStr(mib_tree_entry *root, const char *str)
890 {
891 oid *name;
892 int namelen;
893 mib_tree_entry *e;
894
895 if (root)
896 e = root;
897 else
898 e = mib_tree_head;
899
900 if (! snmpCreateOidFromStr(str, &name, &namelen))
901 return NULL;
902
903 /* I wish there were some kind of sensible existing tree traversal
904 * routine to use. I'll worry about that later */
905 if (namelen <= 1) {
906 xfree(name);
907 return e; /* XXX it should only be this? */
908 }
909
910 int i, r = 1;
911 while (r < namelen) {
912
913 /* Find the child node which matches this */
914 for (i = 0; i < e->children && e->leaves[i]->name[r] != name[r]; ++i) ; // seek-loop
915
916 /* Are we pointing to that node? */
917 if (i >= e->children)
918 break;
919 assert(e->leaves[i]->name[r] == name[r]);
920
921 /* Skip to that node! */
922 e = e->leaves[i];
923 ++r;
924 }
925
926 xfree(name);
927 return e;
928 }
929
930 bool
931 snmpCreateOidFromStr(const char *str, oid **name, int *nl)
932 {
933 char const *delim = ".";
934
935 *name = NULL;
936 *nl = 0;
937 const char *s = str;
938
939 /* Parse the OID string into oid bits */
940 while (size_t len = strcspn(s, delim)) {
941 *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1));
942 (*name)[*nl] = atoi(s); // stops at the '.' delimiter
943 ++(*nl);
944 // exit with true when the last octet has been parsed
945 if (s[len] == '\0')
946 return true;
947 s += len+1;
948 }
949
950 // if we aborted before the lst octet was found, return false.
951 safe_free(name);
952 return false;
953 }
954
955 /*
956 * Create an entry. Return a pointer to the newly created node, or NULL
957 * on failure.
958 */
959 static mib_tree_entry *
960 snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType)
961 {
962 mib_tree_entry *m, *b;
963 oid *n;
964 int nl;
965 char s[1024];
966
967 /* Find base node */
968 b = snmpLookupNodeStr(mib_tree_head, base_str);
969 if (! b)
970 return NULL;
971 debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b);
972
973 /* Create OID string for new entry */
974 snprintf(s, 1024, "%s.%d", base_str, o);
975 if (! snmpCreateOidFromStr(s, &n, &nl))
976 return NULL;
977
978 /* Create a node */
979 m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0);
980
981 /* Link it into the existing tree */
982 snmpAddNodeChild(b, m);
983
984 /* Return the node */
985 return m;
986 }
987
988 /*
989 * Adds a node to the MIB tree structure and adds the appropriate children
990 */
991 static mib_tree_entry *
992 snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...)
993 {
994 va_list args;
995 int loop;
996 mib_tree_entry *entry = NULL;
997 va_start(args, children);
998
999 MemBuf tmp;
1000 debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp));
1001
1002 va_start(args, children);
1003 entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry));
1004 entry->name = name;
1005 entry->len = len;
1006 entry->parsefunction = parsefunction;
1007 entry->instancefunction = instancefunction;
1008 entry->children = children;
1009 entry->leaves = NULL;
1010 entry->aggrType = aggrType;
1011
1012 if (children > 0) {
1013 entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children);
1014
1015 for (loop = 0; loop < children; ++loop) {
1016 entry->leaves[loop] = va_arg(args, mib_tree_entry *);
1017 entry->leaves[loop]->parent = entry;
1018 }
1019 }
1020
1021 va_end(args);
1022 return (entry);
1023 }
1024 /* End of tree utility functions */
1025
1026 /*
1027 * Returns the list of parameters in an oid
1028 */
1029 static oid *
1030 snmpCreateOid(int length,...)
1031 {
1032 va_list args;
1033 oid *new_oid;
1034 int loop;
1035 va_start(args, length);
1036
1037 new_oid = (oid *)xmalloc(sizeof(oid) * length);
1038
1039 if (length > 0) {
1040 for (loop = 0; loop < length; ++loop) {
1041 new_oid[loop] = va_arg(args, int);
1042 }
1043 }
1044
1045 va_end(args);
1046 return (new_oid);
1047 }
1048
1049 /*
1050 * Debug calls, prints out the OID for debugging purposes.
1051 */
1052 const char *
1053 snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf)
1054 {
1055 char mbuf[16];
1056 int x;
1057 if (outbuf.isNull())
1058 outbuf.init(16, MAX_IPSTRLEN);
1059
1060 for (x = 0; x < Len; ++x) {
1061 size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
1062 outbuf.append(mbuf, bytes);
1063 }
1064 return outbuf.content();
1065 }
1066
1067 void
1068 snmpSnmplibDebug(int lvl, char *buf)
1069 {
1070 debugs(49, lvl, buf);
1071 }
1072
1073 /*
1074 IPv4 address: 10.10.0.9 ==>
1075 oid == 10.10.0.9
1076 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1077 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
1078 */
1079 void
1080 addr2oid(Ip::Address &addr, oid * Dest)
1081 {
1082 u_int i ;
1083 u_char *cp = NULL;
1084 struct in_addr i4addr;
1085 struct in6_addr i6addr;
1086 oid code = addr.isIPv6()? INETADDRESSTYPE_IPV6 : INETADDRESSTYPE_IPV4 ;
1087 u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr);
1088 // Dest[0] = code ;
1089 if ( code == INETADDRESSTYPE_IPV4 ) {
1090 addr.getInAddr(i4addr);
1091 cp = (u_char *) &(i4addr.s_addr);
1092 } else {
1093 addr.getInAddr(i6addr);
1094 cp = (u_char *) &i6addr;
1095 }
1096 for ( i=0 ; i < size ; ++i) {
1097 // OID's are in network order
1098 Dest[i] = *cp;
1099 ++cp;
1100 }
1101 MemBuf tmp;
1102 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp));
1103 }
1104
1105 /*
1106 oid == 10.10.0.9 ==>
1107 IPv4 address: 10.10.0.9
1108 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
1109 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1110 */
1111 void
1112 oid2addr(oid * id, Ip::Address &addr, u_int size)
1113 {
1114 struct in_addr i4addr;
1115 struct in6_addr i6addr;
1116 u_int i;
1117 u_char *cp;
1118 if ( size == sizeof(struct in_addr) )
1119 cp = (u_char *) &(i4addr.s_addr);
1120 else
1121 cp = (u_char *) &(i6addr);
1122 MemBuf tmp;
1123 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) );
1124 for (i=0 ; i<size; ++i) {
1125 cp[i] = id[i];
1126 }
1127 if ( size == sizeof(struct in_addr) )
1128 addr = i4addr;
1129 else
1130 addr = i6addr;
1131 }
1132
1133 /* SNMP checklists */
1134 #include "acl/Strategised.h"
1135 #include "acl/Strategy.h"
1136 #include "acl/StringData.h"
1137
1138 class ACLSNMPCommunityStrategy : public ACLStrategy<char const *>
1139 {
1140
1141 public:
1142 virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
1143 static ACLSNMPCommunityStrategy *Instance();
1144 /* Not implemented to prevent copies of the instance. */
1145 /* Not private to prevent brain dead g++ warnings about
1146 * private constructors with no friends */
1147 ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy const &);
1148
1149 private:
1150 static ACLSNMPCommunityStrategy Instance_;
1151 ACLSNMPCommunityStrategy() {}
1152
1153 ACLSNMPCommunityStrategy&operator=(ACLSNMPCommunityStrategy const &);
1154 };
1155
1156 class ACLSNMPCommunity
1157 {
1158
1159 private:
1160 static ACL::Prototype RegistryProtoype;
1161 static ACLStrategised<char const *> RegistryEntry_;
1162 };
1163
1164 ACL::Prototype ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_, "snmp_community");
1165 ACLStrategised<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData, ACLSNMPCommunityStrategy::Instance(), "snmp_community");
1166
1167 int
1168 ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
1169 {
1170 return data->match (checklist->snmp_community);
1171 }
1172
1173 ACLSNMPCommunityStrategy *
1174 ACLSNMPCommunityStrategy::Instance()
1175 {
1176 return &Instance_;
1177 }
1178
1179 ACLSNMPCommunityStrategy ACLSNMPCommunityStrategy::Instance_;
1180