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