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