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