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