]> git.ipfire.org Git - thirdparty/squid.git/blame - src/snmp_core.cc
Prep for 3.3.12 and 3.4.4
[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);
5a429fae 62bool 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
5a429fae 954bool
c5753707
AJ
955snmpCreateOidFromStr(const char *str, oid **name, int *nl)
956{
957 char const *delim = ".";
c5753707
AJ
958
959 *name = NULL;
960 *nl = 0;
5a429fae 961 const char *s = str;
c5753707
AJ
962
963 /* Parse the OID string into oid bits */
5a429fae 964 while (size_t len = strcspn(s, delim)) {
c5753707 965 *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1));
5a429fae 966 (*name)[*nl] = atoi(s); // stops at the '.' delimiter
5db6bf73 967 ++(*nl);
e2de742c 968 // exit with true when the last octet has been parsed
5a429fae
AJ
969 if (s[len] == '\0')
970 return true;
971 s += len+1;
c5753707
AJ
972 }
973
5a429fae 974 // if we aborted before the lst octet was found, return false.
e2de742c 975 safe_free(name);
5a429fae 976 return false;
c5753707
AJ
977}
978
979/*
980 * Create an entry. Return a pointer to the newly created node, or NULL
981 * on failure.
982 */
983static mib_tree_entry *
51ea0904 984snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType)
c5753707
AJ
985{
986 mib_tree_entry *m, *b;
987 oid *n;
988 int nl;
989 char s[1024];
990
991 /* Find base node */
992 b = snmpLookupNodeStr(mib_tree_head, base_str);
993 if (! b)
994 return NULL;
995 debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b);
996
997 /* Create OID string for new entry */
998 snprintf(s, 1024, "%s.%d", base_str, o);
999 if (! snmpCreateOidFromStr(s, &n, &nl))
1000 return NULL;
1001
1002 /* Create a node */
51ea0904 1003 m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0);
c5753707
AJ
1004
1005 /* Link it into the existing tree */
1006 snmpAddNodeChild(b, m);
1007
1008 /* Return the node */
1009 return m;
1010}
1011
d439f213 1012/*
1013 * Adds a node to the MIB tree structure and adds the appropriate children
1014 */
9bc73deb 1015static mib_tree_entry *
51ea0904 1016snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...)
d439f213 1017{
1018 va_list args;
1019 int loop;
1020 mib_tree_entry *entry = NULL;
b6a2f15e 1021 va_start(args, children);
d439f213 1022
6a644e75
AJ
1023 MemBuf tmp;
1024 debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp));
d439f213 1025
b6a2f15e 1026 va_start(args, children);
e6ccf245 1027 entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry));
6ccbae85 1028 entry->name = name;
b6a2f15e 1029 entry->len = len;
1030 entry->parsefunction = parsefunction;
1031 entry->instancefunction = instancefunction;
1032 entry->children = children;
c5753707 1033 entry->leaves = NULL;
51ea0904 1034 entry->aggrType = aggrType;
d439f213 1035
26ac0430 1036 if (children > 0) {
62e76326 1037 entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children);
1038
5db6bf73 1039 for (loop = 0; loop < children; ++loop) {
62e76326 1040 entry->leaves[loop] = va_arg(args, mib_tree_entry *);
1041 entry->leaves[loop]->parent = entry;
1042 }
d439f213 1043 }
62e76326 1044
474067a6 1045 va_end(args);
d439f213 1046 return (entry);
1047}
1048/* End of tree utility functions */
1049
62e76326 1050/*
61d53e64 1051 * Returns the list of parameters in an oid
c68e9c6b 1052 */
9bc73deb 1053static oid *
c68e9c6b 1054snmpCreateOid(int length,...)
dba79ac5 1055{
c68e9c6b 1056 va_list args;
1057 oid *new_oid;
1058 int loop;
c68e9c6b 1059 va_start(args, length);
8a6218c6 1060
e6ccf245 1061 new_oid = (oid *)xmalloc(sizeof(oid) * length);
c68e9c6b 1062
26ac0430 1063 if (length > 0) {
5db6bf73 1064 for (loop = 0; loop < length; ++loop) {
62e76326 1065 new_oid[loop] = va_arg(args, int);
1066 }
c68e9c6b 1067 }
62e76326 1068
7bd339f6 1069 va_end(args);
c68e9c6b 1070 return (new_oid);
43d4303e 1071}
1072
dba79ac5 1073/*
c68e9c6b 1074 * Debug calls, prints out the OID for debugging purposes.
1075 */
6a644e75
AJ
1076const char *
1077snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf)
c68e9c6b 1078{
6a644e75 1079 char mbuf[16];
dba79ac5 1080 int x;
6a644e75
AJ
1081 if (outbuf.isNull())
1082 outbuf.init(16, MAX_IPSTRLEN);
43d4303e 1083
5db6bf73 1084 for (x = 0; x < Len; ++x) {
6a644e75
AJ
1085 size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
1086 outbuf.append(mbuf, bytes);
43d4303e 1087 }
6a644e75 1088 return outbuf.content();
43d4303e 1089}
b644367b 1090
daacd51f 1091void
dba79ac5 1092snmpSnmplibDebug(int lvl, char *buf)
c68e9c6b 1093{
96e03dd8 1094 debugs(49, lvl, buf);
c68e9c6b 1095}
b6a2f15e 1096
26ac0430 1097/*
cc192b50 1098 IPv4 address: 10.10.0.9 ==>
26ac0430
AJ
1099 oid == 10.10.0.9
1100 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1101 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
cc192b50 1102*/
1103void
b7ac5457 1104addr2oid(Ip::Address &addr, oid * Dest)
b6a2f15e 1105{
26ac0430
AJ
1106 u_int i ;
1107 u_char *cp = NULL;
2305bd9b 1108 struct in_addr i4addr;
26ac0430 1109 struct in6_addr i6addr;
4dd643d5 1110 oid code = addr.isIPv6()? INETADDRESSTYPE_IPV6 : INETADDRESSTYPE_IPV4 ;
26ac0430 1111 u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr);
26ac0430
AJ
1112 // Dest[0] = code ;
1113 if ( code == INETADDRESSTYPE_IPV4 ) {
4dd643d5 1114 addr.getInAddr(i4addr);
2305bd9b
AJ
1115 cp = (u_char *) &(i4addr.s_addr);
1116 } else {
4dd643d5 1117 addr.getInAddr(i6addr);
26ac0430
AJ
1118 cp = (u_char *) &i6addr;
1119 }
5db6bf73 1120 for ( i=0 ; i < size ; ++i) {
26ac0430 1121 // OID's are in network order
5db6bf73
FC
1122 Dest[i] = *cp;
1123 ++cp;
cc192b50 1124 }
6a644e75
AJ
1125 MemBuf tmp;
1126 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp));
b6a2f15e 1127}
1128
26ac0430 1129/*
cc192b50 1130 oid == 10.10.0.9 ==>
1131 IPv4 address: 10.10.0.9
26ac0430 1132 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
cc192b50 1133 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1134*/
1135void
b7ac5457 1136oid2addr(oid * id, Ip::Address &addr, u_int size)
b6a2f15e 1137{
2305bd9b
AJ
1138 struct in_addr i4addr;
1139 struct in6_addr i6addr;
26ac0430
AJ
1140 u_int i;
1141 u_char *cp;
26ac0430 1142 if ( size == sizeof(struct in_addr) )
2305bd9b 1143 cp = (u_char *) &(i4addr.s_addr);
26ac0430
AJ
1144 else
1145 cp = (u_char *) &(i6addr);
6a644e75
AJ
1146 MemBuf tmp;
1147 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) );
5db6bf73 1148 for (i=0 ; i<size; ++i) {
26ac0430 1149 cp[i] = id[i];
cc192b50 1150 }
26ac0430 1151 if ( size == sizeof(struct in_addr) )
2305bd9b 1152 addr = i4addr;
26ac0430
AJ
1153 else
1154 addr = i6addr;
b6a2f15e 1155}
b0dd28ba 1156
1157/* SNMP checklists */
c0941a6a 1158#include "acl/Strategised.h"
602d9612 1159#include "acl/Strategy.h"
c0941a6a 1160#include "acl/StringData.h"
b0dd28ba 1161
1162class ACLSNMPCommunityStrategy : public ACLStrategy<char const *>
1163{
1164
1165public:
33810b1d 1166 virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
b0dd28ba 1167 static ACLSNMPCommunityStrategy *Instance();
1168 /* Not implemented to prevent copies of the instance. */
f412b2d6 1169 /* Not private to prevent brain dead g++ warnings about
b0dd28ba 1170 * private constructors with no friends */
1171 ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy const &);
1172
1173private:
1174 static ACLSNMPCommunityStrategy Instance_;
26ac0430 1175 ACLSNMPCommunityStrategy() {}
b0dd28ba 1176
1177 ACLSNMPCommunityStrategy&operator=(ACLSNMPCommunityStrategy const &);
1178};
1179
1180class ACLSNMPCommunity
1181{
1182
1183private:
1184 static ACL::Prototype RegistryProtoype;
1185 static ACLStrategised<char const *> RegistryEntry_;
1186};
1187
1188ACL::Prototype ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_, "snmp_community");
1189ACLStrategised<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData, ACLSNMPCommunityStrategy::Instance(), "snmp_community");
1190
1191int
33810b1d 1192ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
b0dd28ba 1193{
1194 return data->match (checklist->snmp_community);
b0dd28ba 1195}
1196
1197ACLSNMPCommunityStrategy *
1198ACLSNMPCommunityStrategy::Instance()
1199{
1200 return &Instance_;
1201}
1202
1203ACLSNMPCommunityStrategy ACLSNMPCommunityStrategy::Instance_;