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