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