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