]> git.ipfire.org Git - thirdparty/squid.git/blame - src/snmp_core.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / snmp_core.cc
CommitLineData
d2afb1f2 1/*
bde978a6 2 * Copyright (C) 1996-2015 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 {
e0236918 371 debugs(49, DBG_IMPORTANT, "snmpHandleUdp: FD " << sock << " recvfrom: " << xstrerror());
dba79ac5 372 }
373}
43d4303e 374
dba79ac5 375/*
376 * Turn SNMP packet into a PDU, check available ACL's
377 */
9bc73deb 378static void
df6c653b 379snmpDecodePacket(SnmpRequest * rq)
dba79ac5 380{
43d4303e 381 struct snmp_pdu *PDU;
382 u_char *Community;
dba79ac5 383 u_char *buf = rq->buf;
384 int len = rq->len;
2efeb0b7
AJ
385 allow_t allow = ACCESS_DENIED;
386
387 if (!Config.accessList.snmp) {
388 debugs(49, DBG_IMPORTANT, "WARNING: snmp_access not configured. agent query DENIED from : " << rq->from);
389 return;
390 }
43d4303e 391
cc192b50 392 debugs(49, 5, HERE << "Called.");
43d4303e 393 PDU = snmp_pdu_create(0);
cc192b50 394 /* Allways answer on SNMPv1 */
0536fdfc 395 rq->session.Version = SNMP_VERSION_1;
396 Community = snmp_parse(&rq->session, PDU, buf, len);
dba79ac5 397
b50e327b
AJ
398 /* Check if we have explicit permission to access SNMP data.
399 * default (set above) is to deny all */
2efeb0b7 400 if (Community) {
c0941a6a 401 ACLFilledChecklist checklist(Config.accessList.snmp, NULL, NULL);
cc192b50 402 checklist.src_addr = rq->from;
d148d5fb 403 checklist.snmp_community = (char *) Community;
b448c119 404 allow = checklist.fastCheck();
62e76326 405
2efeb0b7
AJ
406 if (allow == ACCESS_ALLOWED && (snmp_coexist_V2toV1(PDU))) {
407 rq->community = Community;
408 rq->PDU = PDU;
409 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]");
410 snmpConstructReponse(rq);
411 } else {
412 debugs(49, DBG_IMPORTANT, "WARNING: SNMP agent query DENIED from : " << rq->from);
413 }
414 xfree(Community);
415
dba79ac5 416 } else {
2efeb0b7 417 debugs(49, DBG_IMPORTANT, "WARNING: Failed SNMP agent query from : " << rq->from);
62e76326 418 snmp_free_pdu(PDU);
43d4303e 419 }
dba79ac5 420}
43d4303e 421
dba79ac5 422/*
423 * Packet OK, ACL Check OK, Create reponse.
424 */
9bc73deb 425static void
df6c653b 426snmpConstructReponse(SnmpRequest * rq)
dba79ac5 427{
62e76326 428
dba79ac5 429 struct snmp_pdu *RespPDU;
74c161ea 430
bf8fe701 431 debugs(49, 5, "snmpConstructReponse: Called.");
51ea0904
CT
432
433 if (UsingSmp() && IamWorkerProcess()) {
434 AsyncJob::Start(new Snmp::Forwarder(static_cast<Snmp::Pdu&>(*rq->PDU),
8fb5a96c 435 static_cast<Snmp::Session&>(rq->session), rq->sock, rq->from));
51ea0904
CT
436 snmp_free_pdu(rq->PDU);
437 return;
438 }
439
dba79ac5 440 RespPDU = snmpAgentResponse(rq->PDU);
441 snmp_free_pdu(rq->PDU);
62e76326 442
ecd2a33f 443 if (RespPDU != NULL) {
0536fdfc 444 snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen);
cc192b50 445 comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen);
62e76326 446 snmp_free_pdu(RespPDU);
43d4303e 447 }
43d4303e 448}
449
dba79ac5 450/*
451 * Decide how to respond to the request, construct a response and
452 * return the response to the requester.
dba79ac5 453 */
62e76326 454
51ea0904 455struct snmp_pdu *
e1381638 456snmpAgentResponse(struct snmp_pdu *PDU) {
62e76326 457
43d4303e 458 struct snmp_pdu *Answer = NULL;
43d4303e 459
bf8fe701 460 debugs(49, 5, "snmpAgentResponse: Called.");
43d4303e 461
26ac0430 462 if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) {
62e76326 463 Answer->reqid = PDU->reqid;
464 Answer->errindex = 0;
465
0536fdfc 466 if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) {
26ac0430 467 /* Indirect way */
0536fdfc 468 int get_next = (PDU->command == SNMP_PDU_GETNEXT);
469 variable_list *VarPtr_;
470 variable_list **RespVars = &(Answer->variables);
471 oid_ParseFn *ParseFn;
472 int index = 0;
62e76326 473 /* Loop through all variables */
474
0536fdfc 475 for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) {
476 variable_list *VarPtr = VarPtr_;
477 variable_list *VarNew = NULL;
478 oid *NextOidName = NULL;
479 snint NextOidNameLen = 0;
62e76326 480
5db6bf73 481 ++index;
62e76326 482
0536fdfc 483 if (get_next)
484 ParseFn = snmpTreeNext(VarPtr->name, VarPtr->name_length, &NextOidName, &NextOidNameLen);
485 else
486 ParseFn = snmpTreeGet(VarPtr->name, VarPtr->name_length);
62e76326 487
488 if (ParseFn == NULL) {
489 Answer->errstat = SNMP_ERR_NOSUCHNAME;
bf8fe701 490 debugs(49, 5, "snmpAgentResponse: No such oid. ");
0536fdfc 491 } else {
492 if (get_next) {
493 VarPtr = snmp_var_new(NextOidName, NextOidNameLen);
494 xfree(NextOidName);
495 }
496
8abf232c 497 int * errstatTmp = &(Answer->errstat);
498
499 VarNew = (*ParseFn) (VarPtr, (snint *) errstatTmp);
62e76326 500
0536fdfc 501 if (get_next)
502 snmp_var_free(VarPtr);
503 }
504
0536fdfc 505 if ((Answer->errstat != SNMP_ERR_NOERROR) || (VarNew == NULL)) {
62e76326 506 Answer->errindex = index;
bf8fe701 507 debugs(49, 5, "snmpAgentResponse: error.");
0536fdfc 508
509 if (VarNew)
510 snmp_var_free(VarNew);
511
0536fdfc 512 while ((VarPtr = Answer->variables) != NULL) {
513 Answer->variables = VarPtr->next_variable;
514 snmp_var_free(VarPtr);
515 }
516
517 /* Steal the original PDU list of variables for the error response */
518 Answer->variables = PDU->variables;
519
520 PDU->variables = NULL;
521
62e76326 522 return (Answer);
523 }
524
525 /* No error. Insert this var at the end, and move on to the next.
526 */
527 *RespVars = VarNew;
528
529 RespVars = &(VarNew->next_variable);
26ac0430
AJ
530 }
531 }
dba79ac5 532 }
62e76326 533
dba79ac5 534 return (Answer);
535}
b644367b 536
9bc73deb 537static oid_ParseFn *
d439f213 538snmpTreeGet(oid * Current, snint CurrentLen)
539{
540 oid_ParseFn *Fn = NULL;
1810dde6 541 mib_tree_entry *mibTreeEntry = NULL;
d439f213 542 int count = 0;
543
bf8fe701 544 debugs(49, 5, "snmpTreeGet: Called");
d439f213 545
6a644e75
AJ
546 MemBuf tmp;
547 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current, CurrentLen, tmp) );
d439f213 548
549 mibTreeEntry = mib_tree_head;
62e76326 550
d439f213 551 if (Current[count] == mibTreeEntry->name[count]) {
5db6bf73 552 ++count;
62e76326 553
554 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
555 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
5db6bf73 556 ++count;
62e76326 557 }
d439f213 558 }
62e76326 559
ec603b25 560 if (mibTreeEntry && mibTreeEntry->parsefunction)
62e76326 561 Fn = mibTreeEntry->parsefunction;
562
bf8fe701 563 debugs(49, 5, "snmpTreeGet: return");
62e76326 564
d439f213 565 return (Fn);
566}
567
51ea0904
CT
568AggrType
569snmpAggrType(oid* Current, snint CurrentLen)
570{
571 debugs(49, 5, HERE);
572
573 mib_tree_entry* mibTreeEntry = mib_tree_head;
574 AggrType type = atNone;
575 int count = 0;
576
577 if (Current[count] == mibTreeEntry->name[count]) {
5db6bf73 578 ++count;
51ea0904
CT
579
580 while (mibTreeEntry != NULL && count < CurrentLen) {
581 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
582 if (mibTreeEntry != NULL)
583 type = mibTreeEntry->aggrType;
5db6bf73 584 ++count;
51ea0904
CT
585 }
586 }
587
588 return type;
589}
590
9bc73deb 591static oid_ParseFn *
dba79ac5 592snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen)
593{
594 oid_ParseFn *Fn = NULL;
dba79ac5 595 int count = 0;
596
bf8fe701 597 debugs(49, 5, "snmpTreeNext: Called");
dba79ac5 598
6a644e75
AJ
599 MemBuf tmp;
600 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp));
b644367b 601
86c9eeb3 602 mib_tree_entry *mibTreeEntry = mib_tree_head;
62e76326 603
86c9eeb3 604 if (mibTreeEntry && Current[count] == mibTreeEntry->name[count]) {
5db6bf73 605 ++count;
62e76326 606
607 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) {
aa6d85ce 608 mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry);
609
26ac0430 610 if (!nextmibTreeEntry)
aa6d85ce 611 break;
612 else
613 mibTreeEntry = nextmibTreeEntry;
614
5db6bf73 615 ++count;
62e76326 616 }
bf8fe701 617 debugs(49, 5, "snmpTreeNext: Recursed down to requested object");
b6a2f15e 618 } else {
62e76326 619 return NULL;
b6a2f15e 620 }
62e76326 621
b6a2f15e 622 if (mibTreeEntry == mib_tree_last)
62e76326 623 return (Fn);
624
cc192b50 625 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
26ac0430
AJ
626 *NextLen = CurrentLen;
627 *Next = (*mibTreeEntry->instancefunction) (Current, NextLen, mibTreeEntry, &Fn);
628 if (*Next) {
6a644e75 629 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
26ac0430
AJ
630 return (Fn);
631 }
b6a2f15e 632 }
62e76326 633
b6a2f15e 634 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) {
5e263176 635 --count;
86c9eeb3 636 mib_tree_entry *nextoid = snmpTreeSiblingEntry(Current[count], count, mibTreeEntry->parent);
62e76326 637 if (nextoid) {
26ac0430 638 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid );
62e76326 639 mibTreeEntry = nextoid;
5db6bf73 640 ++count;
62e76326 641 } else {
bf8fe701 642 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object");
62e76326 643
644 while (!nextoid) {
5e263176 645 --count;
62e76326 646
647 if (mibTreeEntry->parent->parent) {
648 nextoid = mibTreeEntry->parent;
649 mibTreeEntry = snmpTreeEntry(Current[count] + 1, count, nextoid->parent);
650
651 if (!mibTreeEntry) {
652 mibTreeEntry = nextoid;
653 nextoid = NULL;
654 }
655 } else {
656 nextoid = mibTreeEntry;
657 mibTreeEntry = NULL;
658 }
659 }
660 }
b6a2f15e 661 }
662 while ((mibTreeEntry) && (!mibTreeEntry->parsefunction)) {
62e76326 663 mibTreeEntry = mibTreeEntry->leaves[0];
dba79ac5 664 }
62e76326 665
c68e9c6b 666 if (mibTreeEntry) {
62e76326 667 *NextLen = mibTreeEntry->len;
668 *Next = (*mibTreeEntry->instancefunction) (mibTreeEntry->name, NextLen, mibTreeEntry, &Fn);
dba79ac5 669 }
62e76326 670
26ac0430 671 if (*Next) {
6a644e75 672 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp));
26ac0430
AJ
673 return (Fn);
674 } else
62e76326 675 return NULL;
43d4303e 676}
677
9bc73deb 678static oid *
b6a2f15e 679static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
680{
681 oid *instance = NULL;
b6a2f15e 682 if (*len <= current->len) {
5d5ef07e
AJ
683 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
684 memcpy(instance, name, sizeof(*name) * (*len));
62e76326 685 instance[*len] = 0;
686 *len += 1;
b6a2f15e 687 }
688 *Fn = current->parsefunction;
689 return (instance);
690}
691
9bc73deb 692static oid *
b6a2f15e 693time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
694{
695 oid *instance = NULL;
696 int identifier = 0, loop = 0;
cc192b50 697 int index[TIME_INDEX_LEN] = {TIME_INDEX};
b6a2f15e 698
699 if (*len <= current->len) {
5d5ef07e
AJ
700 instance = (oid *)xmalloc(sizeof(*name) * (*len + 1));
701 memcpy(instance, name, sizeof(*name) * (*len));
62e76326 702 instance[*len] = *index;
703 *len += 1;
b6a2f15e 704 } else {
62e76326 705 identifier = name[*len - 1];
706
9bdc291b 707 while ((loop < TIME_INDEX_LEN) && (identifier != index[loop]))
5db6bf73 708 ++loop;
62e76326 709
26ac0430 710 if (loop < (TIME_INDEX_LEN - 1)) {
5d5ef07e
AJ
711 instance = (oid *)xmalloc(sizeof(*name) * (*len));
712 memcpy(instance, name, sizeof(*name) * (*len));
62e76326 713 instance[*len - 1] = index[++loop];
714 }
b6a2f15e 715 }
62e76326 716
b6a2f15e 717 *Fn = current->parsefunction;
718 return (instance);
719}
720
9bc73deb 721static oid *
b6a2f15e 722peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
723{
724 oid *instance = NULL;
a3c6762c 725 CachePeer *peers = Config.peers;
62e76326 726
b6a2f15e 727 if (peers == NULL) {
6f78f0ed 728 debugs(49, 6, "snmp peer_Inst: No Peers.");
62e76326 729 current = current->parent->parent->parent->leaves[1];
62e76326 730 while ((current) && (!current->parsefunction))
731 current = current->leaves[0];
732
b30fe4a7 733 if (!current)
86c9eeb3
AJ
734 return (instance);
735
62e76326 736 instance = client_Inst(current->name, len, current, Fn);
26ac0430 737 } else if (*len <= current->len) {
c5753707 738 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???");
5d5ef07e
AJ
739 instance = (oid *)xmalloc(sizeof(*name) * ( *len + 1));
740 memcpy(instance, name, sizeof(*name) * (*len));
26ac0430
AJ
741 instance[*len] = 1 ;
742 *len += 1;
b6a2f15e 743 } else {
26ac0430 744 int no = name[current->len] ;
c5753707
AJ
745 int i;
746 // Note: This works because the Config.peers keeps its index according to its position.
742a021b 747 for ( i=0 ; peers && (i < no) ; peers = peers->next , ++i ) ;
26ac0430
AJ
748
749 if (peers) {
c5753707 750 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i);
5d5ef07e
AJ
751 instance = (oid *)xmalloc(sizeof(*name) * (current->len + 1 ));
752 memcpy(instance, name, (sizeof(*name) * current->len ));
26ac0430
AJ
753 instance[current->len] = no + 1 ; // i.e. the next index on cache_peeer table.
754 } else {
c5753707 755 debugs(49, 6, "snmp peer_Inst: We have " << i << " peers. Can't find #" << no);
26ac0430
AJ
756 return (instance);
757 }
b6a2f15e 758 }
759 *Fn = current->parsefunction;
760 return (instance);
761}
762
9bc73deb 763static oid *
b6a2f15e 764client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn)
765{
766 oid *instance = NULL;
b7ac5457
AJ
767 Ip::Address laddr;
768 Ip::Address *aux;
dce440dd 769 int size = 0;
770 int newshift = 0;
b6a2f15e 771
26ac0430
AJ
772 if (*len <= current->len) {
773 aux = client_entry(NULL);
774 if (aux)
dce440dd 775 laddr = *aux;
776 else
4dd643d5 777 laddr.setAnyAddr();
cc192b50 778
4dd643d5 779 if (laddr.isIPv4())
dce440dd 780 size = sizeof(in_addr);
dce440dd 781 else
782 size = sizeof(in6_addr);
62e76326 783
6a644e75
AJ
784 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", size=" << size);
785
5d5ef07e
AJ
786 instance = (oid *)xmalloc(sizeof(*name) * (*len + size ));
787 memcpy(instance, name, (sizeof(*name) * (*len)));
62e76326 788
4dd643d5 789 if ( !laddr.isAnyAddr() ) {
dce440dd 790 addr2oid(laddr, &instance[ *len]); // the addr
791 *len += size ;
792 }
cc192b50 793 } else {
26ac0430
AJ
794 int shift = *len - current->len ; // i.e 4 or 16
795 oid2addr(&name[*len - shift], laddr,shift);
796 aux = client_entry(&laddr);
797 if (aux)
dce440dd 798 laddr = *aux;
799 else
4dd643d5 800 laddr.setAnyAddr();
26ac0430 801
4dd643d5
AJ
802 if (!laddr.isAnyAddr()) {
803 if (laddr.isIPv4())
dce440dd 804 newshift = sizeof(in_addr);
dce440dd 805 else
806 newshift = sizeof(in6_addr);
6a644e75
AJ
807
808 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", newshift=" << newshift);
809
5d5ef07e
AJ
810 instance = (oid *)xmalloc(sizeof(*name) * (current->len + newshift));
811 memcpy(instance, name, (sizeof(*name) * (current->len)));
dce440dd 812 addr2oid(laddr, &instance[current->len]); // the addr.
813 *len = current->len + newshift ;
814 }
cc192b50 815 }
26ac0430 816
b6a2f15e 817 *Fn = current->parsefunction;
818 return (instance);
819}
820
b6a2f15e 821/*
822 * Utility functions
823 */
824
825/*
26ac0430 826 * Tree utility functions.
b6a2f15e 827 */
828
62e76326 829/*
cc192b50 830 * Returns a sibling object for the requested child object or NULL
831 * if it does not exit
b6a2f15e 832 */
9bc73deb 833static mib_tree_entry *
897029fd 834snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current)
43d4303e 835{
dba79ac5 836 mib_tree_entry *next = NULL;
837 int count = 0;
8a6218c6 838
897029fd 839 while ((!next) && (count < current->children)) {
62e76326 840 if (current->leaves[count]->name[len] == entry) {
841 next = current->leaves[count];
842 }
843
5db6bf73 844 ++count;
897029fd 845 }
62e76326 846
c5753707 847 /* Exactly the sibling on right */
8a6218c6 848 if (count < current->children) {
62e76326 849 next = current->leaves[count];
8a6218c6 850 } else {
62e76326 851 next = NULL;
897029fd 852 }
62e76326 853
897029fd 854 return (next);
855}
665bc266 856
62e76326 857/*
b6a2f15e 858 * Returns the requested child object or NULL if it does not exist
859 */
9bc73deb 860static mib_tree_entry *
897029fd 861snmpTreeEntry(oid entry, snint len, mib_tree_entry * current)
862{
863 mib_tree_entry *next = NULL;
864 int count = 0;
43d4303e 865
263f9f5f 866 while ((!next) && current && (count < current->children)) {
62e76326 867 if (current->leaves[count]->name[len] == entry) {
868 next = current->leaves[count];
869 }
870
5db6bf73 871 ++count;
43d4303e 872 }
62e76326 873
dba79ac5 874 return (next);
875}
43d4303e 876
c5753707
AJ
877void
878snmpAddNodeChild(mib_tree_entry *entry, mib_tree_entry *child)
879{
880 debugs(49, 5, "snmpAddNodeChild: assigning " << child << " to parent " << entry);
881 entry->leaves = (mib_tree_entry **)xrealloc(entry->leaves, sizeof(mib_tree_entry *) * (entry->children + 1));
882 entry->leaves[entry->children] = child;
883 entry->leaves[entry->children]->parent = entry;
5db6bf73 884 ++ entry->children;
c5753707
AJ
885}
886
887mib_tree_entry *
888snmpLookupNodeStr(mib_tree_entry *root, const char *str)
889{
890 oid *name;
891 int namelen;
892 mib_tree_entry *e;
893
894 if (root)
895 e = root;
896 else
897 e = mib_tree_head;
898
899 if (! snmpCreateOidFromStr(str, &name, &namelen))
900 return NULL;
901
902 /* I wish there were some kind of sensible existing tree traversal
903 * routine to use. I'll worry about that later */
904 if (namelen <= 1) {
905 xfree(name);
906 return e; /* XXX it should only be this? */
907 }
908
909 int i, r = 1;
518c778a 910 while (r < namelen) {
c5753707
AJ
911
912 /* Find the child node which matches this */
5db6bf73 913 for (i = 0; i < e->children && e->leaves[i]->name[r] != name[r]; ++i) ; // seek-loop
c5753707
AJ
914
915 /* Are we pointing to that node? */
916 if (i >= e->children)
917 break;
918 assert(e->leaves[i]->name[r] == name[r]);
919
920 /* Skip to that node! */
921 e = e->leaves[i];
5db6bf73 922 ++r;
c5753707
AJ
923 }
924
925 xfree(name);
926 return e;
927}
928
5a429fae 929bool
c5753707
AJ
930snmpCreateOidFromStr(const char *str, oid **name, int *nl)
931{
932 char const *delim = ".";
c5753707
AJ
933
934 *name = NULL;
935 *nl = 0;
5a429fae 936 const char *s = str;
c5753707
AJ
937
938 /* Parse the OID string into oid bits */
5a429fae 939 while (size_t len = strcspn(s, delim)) {
c5753707 940 *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1));
5a429fae 941 (*name)[*nl] = atoi(s); // stops at the '.' delimiter
5db6bf73 942 ++(*nl);
e2de742c 943 // exit with true when the last octet has been parsed
5a429fae
AJ
944 if (s[len] == '\0')
945 return true;
946 s += len+1;
c5753707
AJ
947 }
948
5a429fae 949 // if we aborted before the lst octet was found, return false.
e2de742c 950 safe_free(name);
5a429fae 951 return false;
c5753707
AJ
952}
953
954/*
955 * Create an entry. Return a pointer to the newly created node, or NULL
956 * on failure.
957 */
958static mib_tree_entry *
51ea0904 959snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType)
c5753707
AJ
960{
961 mib_tree_entry *m, *b;
962 oid *n;
963 int nl;
964 char s[1024];
965
966 /* Find base node */
967 b = snmpLookupNodeStr(mib_tree_head, base_str);
968 if (! b)
969 return NULL;
970 debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b);
971
972 /* Create OID string for new entry */
973 snprintf(s, 1024, "%s.%d", base_str, o);
974 if (! snmpCreateOidFromStr(s, &n, &nl))
975 return NULL;
976
977 /* Create a node */
51ea0904 978 m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0);
c5753707
AJ
979
980 /* Link it into the existing tree */
981 snmpAddNodeChild(b, m);
982
983 /* Return the node */
984 return m;
985}
986
d439f213 987/*
988 * Adds a node to the MIB tree structure and adds the appropriate children
989 */
9bc73deb 990static mib_tree_entry *
51ea0904 991snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...)
d439f213 992{
993 va_list args;
994 int loop;
995 mib_tree_entry *entry = NULL;
b6a2f15e 996 va_start(args, children);
d439f213 997
6a644e75
AJ
998 MemBuf tmp;
999 debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp));
d439f213 1000
b6a2f15e 1001 va_start(args, children);
e6ccf245 1002 entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry));
6ccbae85 1003 entry->name = name;
b6a2f15e 1004 entry->len = len;
1005 entry->parsefunction = parsefunction;
1006 entry->instancefunction = instancefunction;
1007 entry->children = children;
c5753707 1008 entry->leaves = NULL;
51ea0904 1009 entry->aggrType = aggrType;
d439f213 1010
26ac0430 1011 if (children > 0) {
62e76326 1012 entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children);
1013
5db6bf73 1014 for (loop = 0; loop < children; ++loop) {
62e76326 1015 entry->leaves[loop] = va_arg(args, mib_tree_entry *);
1016 entry->leaves[loop]->parent = entry;
1017 }
d439f213 1018 }
62e76326 1019
474067a6 1020 va_end(args);
d439f213 1021 return (entry);
1022}
1023/* End of tree utility functions */
1024
62e76326 1025/*
61d53e64 1026 * Returns the list of parameters in an oid
c68e9c6b 1027 */
9bc73deb 1028static oid *
c68e9c6b 1029snmpCreateOid(int length,...)
dba79ac5 1030{
c68e9c6b 1031 va_list args;
1032 oid *new_oid;
1033 int loop;
c68e9c6b 1034 va_start(args, length);
8a6218c6 1035
e6ccf245 1036 new_oid = (oid *)xmalloc(sizeof(oid) * length);
c68e9c6b 1037
26ac0430 1038 if (length > 0) {
5db6bf73 1039 for (loop = 0; loop < length; ++loop) {
62e76326 1040 new_oid[loop] = va_arg(args, int);
1041 }
c68e9c6b 1042 }
62e76326 1043
7bd339f6 1044 va_end(args);
c68e9c6b 1045 return (new_oid);
43d4303e 1046}
1047
dba79ac5 1048/*
c68e9c6b 1049 * Debug calls, prints out the OID for debugging purposes.
1050 */
6a644e75
AJ
1051const char *
1052snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf)
c68e9c6b 1053{
6a644e75 1054 char mbuf[16];
dba79ac5 1055 int x;
6a644e75
AJ
1056 if (outbuf.isNull())
1057 outbuf.init(16, MAX_IPSTRLEN);
43d4303e 1058
5db6bf73 1059 for (x = 0; x < Len; ++x) {
6a644e75
AJ
1060 size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]);
1061 outbuf.append(mbuf, bytes);
43d4303e 1062 }
6a644e75 1063 return outbuf.content();
43d4303e 1064}
b644367b 1065
daacd51f 1066void
dba79ac5 1067snmpSnmplibDebug(int lvl, char *buf)
c68e9c6b 1068{
96e03dd8 1069 debugs(49, lvl, buf);
c68e9c6b 1070}
b6a2f15e 1071
26ac0430 1072/*
cc192b50 1073 IPv4 address: 10.10.0.9 ==>
26ac0430
AJ
1074 oid == 10.10.0.9
1075 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==>
1076 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1
cc192b50 1077*/
1078void
b7ac5457 1079addr2oid(Ip::Address &addr, oid * Dest)
b6a2f15e 1080{
26ac0430
AJ
1081 u_int i ;
1082 u_char *cp = NULL;
2305bd9b 1083 struct in_addr i4addr;
26ac0430 1084 struct in6_addr i6addr;
4dd643d5 1085 oid code = addr.isIPv6()? INETADDRESSTYPE_IPV6 : INETADDRESSTYPE_IPV4 ;
26ac0430 1086 u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr);
26ac0430
AJ
1087 // Dest[0] = code ;
1088 if ( code == INETADDRESSTYPE_IPV4 ) {
4dd643d5 1089 addr.getInAddr(i4addr);
2305bd9b
AJ
1090 cp = (u_char *) &(i4addr.s_addr);
1091 } else {
4dd643d5 1092 addr.getInAddr(i6addr);
26ac0430
AJ
1093 cp = (u_char *) &i6addr;
1094 }
5db6bf73 1095 for ( i=0 ; i < size ; ++i) {
26ac0430 1096 // OID's are in network order
5db6bf73
FC
1097 Dest[i] = *cp;
1098 ++cp;
cc192b50 1099 }
6a644e75
AJ
1100 MemBuf tmp;
1101 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp));
b6a2f15e 1102}
1103
26ac0430 1104/*
cc192b50 1105 oid == 10.10.0.9 ==>
1106 IPv4 address: 10.10.0.9
26ac0430 1107 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==>
cc192b50 1108 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01
1109*/
1110void
b7ac5457 1111oid2addr(oid * id, Ip::Address &addr, u_int size)
b6a2f15e 1112{
2305bd9b
AJ
1113 struct in_addr i4addr;
1114 struct in6_addr i6addr;
26ac0430
AJ
1115 u_int i;
1116 u_char *cp;
26ac0430 1117 if ( size == sizeof(struct in_addr) )
2305bd9b 1118 cp = (u_char *) &(i4addr.s_addr);
26ac0430
AJ
1119 else
1120 cp = (u_char *) &(i6addr);
6a644e75
AJ
1121 MemBuf tmp;
1122 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) );
5db6bf73 1123 for (i=0 ; i<size; ++i) {
26ac0430 1124 cp[i] = id[i];
cc192b50 1125 }
26ac0430 1126 if ( size == sizeof(struct in_addr) )
2305bd9b 1127 addr = i4addr;
26ac0430
AJ
1128 else
1129 addr = i6addr;
b6a2f15e 1130}
b0dd28ba 1131
1132/* SNMP checklists */
c0941a6a 1133#include "acl/Strategised.h"
602d9612 1134#include "acl/Strategy.h"
c0941a6a 1135#include "acl/StringData.h"
b0dd28ba 1136
1137class ACLSNMPCommunityStrategy : public ACLStrategy<char const *>
1138{
1139
1140public:
33810b1d 1141 virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
b0dd28ba 1142 static ACLSNMPCommunityStrategy *Instance();
1143 /* Not implemented to prevent copies of the instance. */
f412b2d6 1144 /* Not private to prevent brain dead g++ warnings about
b0dd28ba 1145 * private constructors with no friends */
1146 ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy const &);
1147
1148private:
1149 static ACLSNMPCommunityStrategy Instance_;
26ac0430 1150 ACLSNMPCommunityStrategy() {}
b0dd28ba 1151
1152 ACLSNMPCommunityStrategy&operator=(ACLSNMPCommunityStrategy const &);
1153};
1154
1155class ACLSNMPCommunity
1156{
1157
1158private:
1159 static ACL::Prototype RegistryProtoype;
1160 static ACLStrategised<char const *> RegistryEntry_;
1161};
1162
1163ACL::Prototype ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_, "snmp_community");
1164ACLStrategised<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData, ACLSNMPCommunityStrategy::Instance(), "snmp_community");
1165
1166int
33810b1d 1167ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &)
b0dd28ba 1168{
1169 return data->match (checklist->snmp_community);
b0dd28ba 1170}
1171
1172ACLSNMPCommunityStrategy *
1173ACLSNMPCommunityStrategy::Instance()
1174{
1175 return &Instance_;
1176}
1177
1178ACLSNMPCommunityStrategy ACLSNMPCommunityStrategy::Instance_;
f53969cc 1179