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