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