1 // NAME
2 // $RCSfile: UsmDiscoveryBean.java,v $
3 // DESCRIPTION
4 // [given below in javadoc format]
5 // DELTA
6 // $Revision: 1.21 $
7 // CREATED
8 // $Date: 2009/03/05 15:51:42 $
9 // COPYRIGHT
10 // Westhawk Ltd
11 // TO DO
12 //
13
14 /*
15 * Copyright (C) 2000 - 2006 by Westhawk Ltd
16 *
17 * Permission to use, copy, modify, and distribute this software
18 * for any purpose and without fee is hereby granted, provided
19 * that the above copyright notices appear in all copies and that
20 * both the copyright notice and this permission notice appear in
21 * supporting documentation.
22 * This software is provided "as is" without express or implied
23 * warranty.
24 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
25 */
26
27 package uk.co.westhawk.snmp.beans;
28
29 /*-
30 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
31 * SNMP Java Client
32 * ჻჻჻჻჻჻
33 * Copyright 2023 MetricsHub, Westhawk
34 * ჻჻჻჻჻჻
35 * This program is free software: you can redistribute it and/or modify
36 * it under the terms of the GNU Lesser General Public License as
37 * published by the Free Software Foundation, either version 3 of the
38 * License, or (at your option) any later version.
39 *
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Lesser Public License for more details.
44 *
45 * You should have received a copy of the GNU General Lesser Public
46 * License along with this program. If not, see
47 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
48 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
49 */
50
51 import uk.co.westhawk.snmp.stack.*;
52 import uk.co.westhawk.snmp.pdu.*;
53 import java.util.*;
54
55 /**
56 * <p>
57 * This bean performs the SNMPv3 USM discovery process.
58 * </p>
59 *
60 * <p>
61 * The process consists of two steps: first the SNMP engine ID has to be
62 * discovered, second the timeline details of the SNMP engine ID have to
63 * be discovered. For the last step the username of the principal is
64 * needed.
65 * </p>
66 *
67 * <p>
68 * See <a href="http://www.ietf.org/rfc/rfc3414.txt">SNMP-USER-BASED-SM-MIB</a>.
69 * </p>
70 *
71 * @author <a href="mailto:snmp@westhawk.co.uk">Birgit Arkesteijn</a>
72 * @version $Revision: 1.21 $ $Date: 2009/03/05 15:51:42 $
73 */
74 public class UsmDiscoveryBean {
75 private static final String version_id = "@(#)$Id: UsmDiscoveryBean.java,v 1.21 2009/03/05 15:51:42 birgita Exp $ Copyright Westhawk Ltd";
76
77 private SnmpContextv3Pool context;
78 private String userName = null;
79 private String userAuthPassword = null;
80 private String userPrivPassword = null;
81 private int authProtocol, privProtocol;
82 private int retry_intervals[] = { 500, 1000, 2000, 5000, 5000 };
83
84 /**
85 * Constructor.
86 *
87 * @param host The host to discover
88 * @param port The port to discover
89 * @see SnmpContextv3#SnmpContextv3(String, int)
90 * @see #startDiscovery()
91 */
92 public UsmDiscoveryBean(String host, int port)
93 throws java.io.IOException {
94 this(host, port, null, SnmpContextBasisFace.STANDARD_SOCKET);
95 }
96
97 /**
98 * Constructor.
99 *
100 * @param host The host to discover
101 * @param port The port to discover
102 * @param bindAddr The local address the server will bind to
103 * @param typeSocketA The type of socket to use.
104 *
105 * @see SnmpContextv3#SnmpContextv3(String, int, String, String)
106 * @see #startDiscovery()
107 */
108 public UsmDiscoveryBean(String host, int port, String bindAddr, String typeSocketA)
109 throws java.io.IOException {
110 context = new SnmpContextv3Pool(host, port, bindAddr, typeSocketA);
111 }
112
113 /**
114 * Sets the user's authentication details.
115 * With these details the time line details will be retrieved.
116 * If the user details are not set, only the engine ID will be
117 * discovered.
118 *
119 * <p>
120 * The time line details only need to be known when the user want to
121 * send authenticated message to this SNMP engine.
122 * </p>
123 *
124 * @param newUserName The user name
125 * @param newUserPassword The user authentication password
126 * @param protocol The user authentication protocol
127 *
128 * @see SnmpContextv3#setUserName(String)
129 * @see SnmpContextv3#setUserAuthenticationPassword(String)
130 * @see SnmpContextv3#setAuthenticationProtocol(int)
131 */
132 public void setAuthenticationDetails(String newUserName, String newUserPassword,
133 int protocol) {
134 userName = newUserName;
135 userAuthPassword = newUserPassword;
136 authProtocol = protocol;
137 }
138
139 /**
140 * Sets the user's privacy details.
141 * With these details the time line details will be retrieved if needed.
142 *
143 * <p>
144 * The time line details only need to be known when the user want to
145 * send authenticated message to this SNMP engine.
146 * </p>
147 *
148 * @param newUserPassword The user privacy password
149 *
150 * @see SnmpContextv3#setUserPrivacyPassword(String)
151 */
152 public void setPrivacyDetails(String newUserPassword, int protocol) {
153 userPrivPassword = newUserPassword;
154 privProtocol = protocol;
155 }
156
157 /**
158 * Sets the retry intervals of the PDU. The length of the array
159 * corresponds with the number of retries. Each entry in the array
160 * is the number of milliseconds of each try.
161 *
162 * <p>
163 * If used, please set before sending!
164 * </p>
165 *
166 * The default is {500, 1000, 2000, 5000, 5000}.
167 * It is good practice to make the interval bigger with each retry,
168 * if the numbers are the same the chance of collision is higher.
169 *
170 * @param rinterval The interval in msec of each retry
171 * @see Pdu#setRetryIntervals(int[])
172 */
173 public void setRetryIntervals(int rinterval[]) {
174 retry_intervals = rinterval;
175 }
176
177 /**
178 * Starts the discovery. This method will send a Pdu to discover the
179 * SNMP engine ID. Set the user details before calling this method, if
180 * you want the time line details to be discovered as well.
181 *
182 * <p>
183 * This is a blocking call! It will return when it has done the whole
184 * discovery.
185 * </p>
186 *
187 * @see #setAuthenticationDetails(String, String, int)
188 * @see #discoveryEngineId
189 * @see #discoveryTimeLine
190 */
191 // Thanks to "Cochran, Steve A." <steve@more.net>;
192 // freeResources(); is called before throwing an exception
193 public void startDiscovery()
194 throws PduException, java.io.IOException {
195 try {
196 discoveryEngineId();
197 } catch (PduException exc) {
198 // You shouldn't really get an exception when doing engineID
199 // discovery.
200 freeResources(); // <-- Steve
201 throw new PduException("Engine ID discovery: "
202 + exc.getMessage());
203 }
204
205 try {
206 discoveryTimeLine();
207 } catch (PduException exc) {
208 // You can get an exception for authPriv. I noticed that when
209 // testing against MG-SOFT.
210 // Only throw the exception if the timeline was not discovered.
211
212 TimeWindow tWindow = TimeWindow.getCurrent();
213 String engineId = tWindow.getSnmpEngineId(context.getSendToHostAddress(),
214 context.getPort());
215 if (tWindow.isTimeLineKnown(engineId) == false) {
216 freeResources(); // <-- Steve
217 throw new PduException("Timeline discovery: "
218 + exc.getMessage());
219 }
220 }
221
222 if (AsnObject.debug > 4) {
223 System.out.println(getClass().getName() + ".startDiscovery(): "
224 + "Done, context " + context.toString());
225 }
226
227 freeResources();
228 }
229
230 /**
231 * Destroy the context in use.
232 */
233 public void freeResources() {
234 context.destroy();
235 context = null;
236 }
237
238 /**
239 * Starts the discovery of the SNMP engine ID.
240 *
241 * <p>
242 * This is a blocking call! It will return when it has done the whole
243 * discovery.
244 * </p>
245 *
246 * @see #startDiscovery
247 * @see #discoveryTimeLine
248 */
249 protected void discoveryEngineId()
250 throws PduException, java.io.IOException {
251 DiscoveryPdu pdu;
252
253 TimeWindow tWindow = TimeWindow.getCurrent();
254 String engineId = tWindow.getSnmpEngineId(context.getHost(),
255 context.getPort());
256
257 // Just check again to be sure
258 if (engineId == null) {
259 if (AsnObject.debug > 4) {
260 System.out.println(getClass().getName() + ".discoveryEngineId(): "
261 + "Starting discovery Engine ID ...");
262 }
263 context.setUserName("");
264 context.setUseAuthentication(false);
265 context.setUsePrivacy(false);
266 context.setContextEngineId(new byte[0]);
267 context.setContextName("");
268
269 pdu = new DiscoveryPdu(context);
270 pdu.setRetryIntervals(retry_intervals);
271 pdu.send();
272 pdu.waitForSelf();
273 varbind[] vars = pdu.getResponseVarbinds();
274 }
275 }
276
277 /**
278 * Starts the discovery of the Time line.
279 *
280 * <p>
281 * This is a blocking call! It will return when it has done the whole
282 * discovery.
283 * </p>
284 *
285 * @see #startDiscovery
286 * @see #discoveryEngineId
287 */
288 protected void discoveryTimeLine()
289 throws PduException, java.io.IOException {
290 DiscoveryPdu pdu;
291
292 TimeWindow tWindow = TimeWindow.getCurrent();
293 String engineId = tWindow.getSnmpEngineId(context.getSendToHostAddress(),
294 context.getPort());
295
296 // The engineId should be known by now.
297 // Only do timeline discovery if it is not known yet.
298 if (tWindow.isTimeLineKnown(engineId) == false && userName != null) {
299 if (AsnObject.debug > 4) {
300 System.out.println(getClass().getName() + ".discoveryTimeLine(): "
301 + "Starting discovery Timeline ...");
302 }
303 context.setUserName(userName);
304 context.setUserAuthenticationPassword(userAuthPassword);
305 context.setUseAuthentication(true);
306 context.setAuthenticationProtocol(authProtocol);
307 context.setContextEngineId(new byte[0]);
308 context.setContextName("");
309
310 if (userPrivPassword != null) {
311 context.setUsePrivacy(true);
312 context.setUserPrivacyPassword(userPrivPassword);
313 context.setPrivacyProtocol(privProtocol);
314 } else {
315 context.setUsePrivacy(false);
316 }
317
318 pdu = new DiscoveryPdu(context);
319 pdu.setRetryIntervals(retry_intervals);
320 pdu.send();
321 pdu.waitForSelf();
322 varbind[] vars = pdu.getResponseVarbinds();
323
324 if (AsnObject.debug > 4) {
325 System.out.println("Did discovery time line");
326 }
327 }
328 }
329
330 }