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