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