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