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