View Javadoc
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 }