KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > agent > mo > snmp > ProxyForwarderImpl


1 /*_############################################################################
2   _##
3   _## SNMP4J-Agent - ProxyForwarderImpl.java
4   _##
5   _## Copyright (C) 2005-2007 Frank Fock (SNMP4J.org)
6   _##
7   _## Licensed under the Apache License, Version 2.0 (the "License");
8   _## you may not use this file except in compliance with the License.
9   _## You may obtain a copy of the License at
10   _##
11   _## http://www.apache.org/licenses/LICENSE-2.0
12   _##
13   _## Unless required by applicable law or agreed to in writing, software
14   _## distributed under the License is distributed on an "AS IS" BASIS,
15   _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   _## See the License for the specific language governing permissions and
17   _## limitations under the License.
18   _##
19   _##########################################################################*/

20
21 package org.snmp4j.agent.mo.snmp;
22
23 import java.io.*;
24 import java.util.*;
25
26 import org.snmp4j.*;
27 import org.snmp4j.agent.*;
28 import org.snmp4j.agent.mo.*;
29 import org.snmp4j.agent.mo.snmp.SnmpProxyMIB.*;
30 import org.snmp4j.agent.mo.snmp.SnmpTargetMIB.*;
31 import org.snmp4j.agent.request.*;
32 import org.snmp4j.agent.security.*;
33 import org.snmp4j.event.*;
34 import org.snmp4j.log.*;
35 import org.snmp4j.mp.*;
36 import org.snmp4j.smi.*;
37 import org.snmp4j.util.*;
38 import java.net.InetAddress JavaDoc;
39
40 /**
41  * The <code>ProxyForwarderImpl</code> class implements a proxy forwarder
42  * instance as defined by RFC 3413. It is configured through the SNMP-PROXY-MIB
43  * and SNMP-TARGET-MIB implementations provided on construction. It sends
44  * notifications through the provided SNMP session.
45  *
46  * @author Frank Fock
47  * @version 1.0
48  */

49 public class ProxyForwarderImpl implements ProxyForwarder {
50
51   private static final LogAdapter logger =
52       LogFactory.getLogger(ProxyForwarderImpl.class);
53
54   private Snmp session;
55   private SnmpProxyMIB proxyMIB;
56   private SnmpTargetMIB targetMIB;
57   private transient Vector counterListeners;
58
59   /**
60    * Creates a <code>ProxyForwarder</code> implementation based on a SNMP
61    * session used to send the notifications and a SNMP-PROXY-MIB
62    * and a SNMP-TARGET-MIB implementation used for its configuration.
63    * @param session
64    * a SNMP session.
65    * @param proxyMIB
66    * a <code>SnmpProxyMIB</code> implementation with the proxy configuration.
67    * @param targetMIB
68    * a <code>SnmpTargetMIB</code> implementation with the target
69    * configuration.
70    */

71   public ProxyForwarderImpl(Snmp session,
72                             SnmpProxyMIB proxyMIB, SnmpTargetMIB targetMIB) {
73     this.session = session;
74     this.proxyMIB = proxyMIB;
75     this.targetMIB = targetMIB;
76   }
77
78   /**
79    * Forwards a <code>Request</code> if it matches the criteria defined by the
80    * SNMP-PROXY-MIB associated with this proxy forwarder.
81    *
82    * @param request
83    * a <code>ProxyForwardRequest</code> encapsuling the forwarding request.
84    * @return
85    * <code>true</code> if the request has been forwarded,
86    * <code>false</code> otherwise.
87    */

88   public boolean forward(ProxyForwardRequest request) {
89     int pduType = request.getCommandEvent().getPDU().getType();
90     if (SnmpRequest.getViewType(pduType) == VACM.VIEW_NOTIFY) {
91       return multipleForward(request);
92     }
93     else {
94       ResponseEvent resp = singleForward(request);
95       if ((resp != null) && (resp.getResponse() != null)) {
96         PDU respPDU = resp.getResponse();
97         PDU translatedResponse = DefaultPDUFactory.createPDU(
98             request.getCommandEvent().getSecurityModel());
99         if (!translatedResponse.getClass().equals(respPDU.getClass())) {
100           // not required PDU instance -> copy data
101
translatedResponse.setType(respPDU.getType());
102           translatedResponse.addAll(respPDU.toArray());
103           translatedResponse.setErrorIndex(respPDU.getErrorIndex());
104           translatedResponse.setErrorStatus(respPDU.getErrorStatus());
105         }
106         else {
107           translatedResponse = respPDU;
108         }
109         if (translatedResponse.getType() == PDU.RESPONSE) {
110           translatedResponse.setRequestID(
111               request.getCommandEvent().getPDU().getRequestID());
112           if ((translatedResponse instanceof ScopedPDU) &&
113               (request.getCommandEvent().getPDU() instanceof ScopedPDU)) {
114             ScopedPDU scopedPDUReq =
115                 (ScopedPDU) request.getCommandEvent().getPDU();
116             ScopedPDU scopedPDUResp = (ScopedPDU) translatedResponse;
117             scopedPDUResp.setContextEngineID(scopedPDUReq.getContextEngineID());
118             scopedPDUResp.setContextName(scopedPDUReq.getContextName());
119           }
120         }
121         request.setResponsePDU(translatedResponse);
122         return true;
123       }
124     }
125     return false;
126   }
127
128   protected List getMatches(ProxyForwardRequest request) {
129     List matches =
130         proxyMIB.getProxyRows(request.getProxyType(),
131                               request.getContextEngineID(),
132                               request.getContext());
133     for (Iterator it = matches.iterator(); it.hasNext(); ) {
134       SnmpProxyRow possibleMatch =
135           (SnmpProxyRow) (MOTableRow) it.next();
136       OctetString paramIn = possibleMatch.getSnmpProxyTargetParamsIn();
137       if (logger.isDebugEnabled()) {
138         logger.debug("Checking possible match for in parameter: "+paramIn);
139       }
140       if (!matchParameters(request, paramIn)) {
141         it.remove();
142       }
143     }
144     return matches;
145   }
146
147   protected boolean matchParameters(ProxyForwardRequest request,
148                                     OctetString paramIn) {
149     MOTableRow param2Match = targetMIB.getTargetParamsRow(paramIn, true);
150     if (param2Match != null) {
151       int mpModel = param2Match.getValue(
152           SnmpTargetMIB.idxSnmpTargetParamsMPModel).toInt();
153       int secModel = param2Match.getValue(
154           SnmpTargetMIB.idxSnmpTargetParamsSecurityModel).toInt();
155       int secLevel = param2Match.getValue(
156           SnmpTargetMIB.idxSnmpTargetParamsSecurityLevel).toInt();
157       OctetString secName = (OctetString) param2Match.getValue(
158           SnmpTargetMIB.idxSnmpTargetParamsSecurityName);
159       if (logger.isDebugEnabled()) {
160         logger.debug("Matching request "+request+" with mpModel="+mpModel+
161                      ", secModel="+secModel+", secLevel="+secLevel+
162                      ", secName="+secName);
163       }
164       if ((mpModel == request.getCommandEvent().getMessageProcessingModel()) &&
165           (secName.equals(request.getSecurityName())) &&
166           ((secModel == 0) ||
167            (secModel == request.getCommandEvent().getSecurityModel())) &&
168           (secLevel == request.getCommandEvent().getSecurityLevel())) {
169         return true;
170       }
171     }
172     return false;
173   }
174
175   protected ResponseEvent singleForward(ProxyForwardRequest request) {
176     List matches = getMatches(request);
177     if ((matches == null) || (matches.isEmpty())) {
178       if (logger.isInfoEnabled()) {
179         logger.info("No matching proxy entry found for contextEngineID="+
180                     request.getContextEngineID()+
181                     ", context="+request.getContext()+" and request="+
182                     request);
183       }
184       return null;
185     }
186     OctetString outParam = (OctetString)
187         ((MOTableRow)
188          matches.get(0)).getValue(SnmpProxyMIB.idxSnmpProxySingleTargetOut);
189     Target target = targetMIB.getTarget(outParam,
190                                         request.getContextEngineID(),
191                                         request.getContext());
192     if (target == null) {
193       if (logger.isInfoEnabled()) {
194         logger.info("No matching target with name '" + outParam + "'");
195       }
196       return null;
197     }
198     // forwarding request
199
if (logger.isInfoEnabled()) {
200       logger.info("Forwarding proxy request "+request+" to "+target);
201     }
202     PDU reqPDU = request.getCommandEvent().getPDU();
203     PDU pdu = DefaultPDUFactory.createPDU(target, reqPDU.getType());
204     setScope(request, pdu);
205     try {
206       proxyForwardTranslation(request, reqPDU, pdu);
207       ResponseEvent response = null;
208       do {
209         response = session.send(pdu, target);
210         if (logger.isInfoEnabled()) {
211           logger.info("Received proxy response from " +
212                       response.getPeerAddress() +
213                       " is " + response.getResponse());
214         }
215       }
216       while (proxyBackwardTranslation(reqPDU, pdu, response));
217       return response;
218     }
219     catch (Exception JavaDoc ex) {
220       if (logger.isDebugEnabled()) {
221         ex.printStackTrace();
222       }
223       logger.error("Failed to send proxy request to "+target+" because: "+
224                    ex.getMessage());
225       fireIncrementCounter(new CounterEvent(this, SnmpConstants.snmpProxyDrops));
226       if (SNMP4JSettings.isFowardRuntimeExceptions()) {
227         throw new RuntimeException JavaDoc(ex);
228       }
229       return null;
230     }
231   }
232
233   protected boolean proxyBackwardTranslation(PDU reqPDU, PDU pdu,
234                                              ResponseEvent response) {
235     if (response.getResponse() == null) {
236       return false;
237     }
238     PDU resp = response.getResponse();
239     if ((resp.getErrorStatus() == PDU.tooBig) &&
240         (reqPDU.getType() != PDU.GETBULK)) {
241       response.getResponse().clear();
242       response.getResponse().setErrorStatus(PDU.noError);
243       response.getResponse().setErrorIndex(0);
244       return false;
245     }
246     if ((resp.getErrorStatus() == PDU.tooBig) &&
247         (reqPDU.getType() == PDU.GETBULK) && (pdu.getType() == PDU.GETBULK)) {
248       /**implemented as defined in RFC 3584 4.3.1(3)*/
249       if (pdu.size() == 1) {
250         response.getResponse().clear();
251         response.getResponse().setErrorStatus(PDU.noError);
252         response.getResponse().setErrorIndex(0);
253         return false;
254       }
255       else {
256         while (pdu.size() > 1) {
257           pdu.trim();
258         }
259         pdu.setType(PDU.GETNEXT);
260         return true;
261       }
262     }
263     if ((reqPDU instanceof PDUv1) &&
264         (!(response.getResponse() instanceof PDUv1))) {
265       boolean resendNeeded = false;
266       for (int i=0; i<resp.size(); i++) {
267         VariableBinding vb = resp.get(i);
268         if (vb.getVariable() instanceof Counter64) {
269           OID nextOID = new OID(vb.getOid());
270           if (nextOID.last() < 65535) {
271             nextOID.set(nextOID.size()-1, 65535);
272           }
273           else {
274             nextOID.set(nextOID.size()-1, OID.MAX_SUBID_VALUE);
275           }
276           pdu.get(i).setOid(vb.getOid());
277           resendNeeded = true;
278         }
279       }
280       if (resendNeeded && (reqPDU.getType() != PDU.GETNEXT)) {
281         throw new IllegalArgumentException JavaDoc(
282             "GET response with Counter64 cannot be proxied");
283       }
284       else {
285         return true;
286       }
287     }
288     return false;
289   }
290
291   /**
292    * Translates a source PDU into the supplied target PDU. The mapping between
293    * the source PDU and the target PDU is done as defined by RFC 3584.
294    * @param request
295    * the proxy forwarding request.
296    * @param source
297    * the source PDU instance.
298    * @param target
299    * the target PDU instance. The variable bindings of the source will
300    * replace any VBs of the target instance. If the source PDU cannot
301    * be converted to the target PDU <code>target</code> is not changed.
302    * Instead an intermediate PDU is returned.
303    */

304   protected void proxyForwardTranslation(ProxyForwardRequest request,
305                                          PDU source, PDU target)
306       throws IllegalArgumentException JavaDoc
307   {
308     target.clear();
309     target.setType(source.getType());
310     if (!(target instanceof PDUv1) && !(source instanceof PDUv1)) {
311       target.setMaxRepetitions(source.getMaxRepetitions());
312       target.setNonRepeaters(source.getNonRepeaters());
313     }
314     if ((source.getType() == PDU.V1TRAP) &&
315         (source instanceof PDUv1) &&
316         (!(target instanceof PDUv1))) {
317       PDUv1 sourceV1 = (PDUv1)source;
318       target.setType(PDU.NOTIFICATION);
319       target.add(new VariableBinding(SnmpConstants.sysUpTime,
320                                      new TimeTicks(sourceV1.getTimestamp())));
321       target.add(new VariableBinding(SnmpConstants.snmpTrapOID,
322                                      SnmpConstants.getTrapOID(
323                                          sourceV1.getEnterprise(),
324                                          sourceV1.getGenericTrap(),
325                                          sourceV1.getSpecificTrap())));
326       target.addAll(source.toArray());
327       target.add(new VariableBinding(SnmpConstants.snmpTrapAddress,
328                                      sourceV1.getAgentAddress()));
329       target.add(new VariableBinding(SnmpConstants.snmpTrapEnterprise,
330                                      sourceV1.getEnterprise()));
331       OctetString community =
332           new OctetString(request.getCommandEvent().getSecurityName());
333       target.add(new VariableBinding(SnmpConstants.snmpTrapCommunity,
334                                      community));
335     }
336     else if (((source.getType() == PDU.NOTIFICATION) ||
337               (source.getType() == PDU.INFORM)) &&
338              (target instanceof PDUv1)) {
339       PDUv1 targetV1 = (PDUv1)target;
340       target.setType(PDU.V1TRAP);
341       if ((source.size() < 2) ||
342           (!(source.get(0).getVariable() instanceof TimeTicks)) ||
343           (!(source.get(1).getVariable() instanceof OID))) {
344         throw new IllegalArgumentException JavaDoc("Proxy source invalid notification PDU: "+
345                                            source);
346       }
347       TimeTicks sysUpTime = (TimeTicks) source.get(0).getVariable();
348       OID trapOID = (OID)source.get(1).getVariable();
349       int genericID = SnmpConstants.getGenericTrapID(trapOID);
350       // RFC 3584 Translating
351
// SNMPv2 notification to SNMPv1 notification parameters
352
if (genericID < 0) {
353         targetV1.setGenericTrap(6);
354         if ((trapOID.size() > 2) && (trapOID.get(trapOID.size() - 2) == 0)) {
355           targetV1.setSpecificTrap(trapOID.get(trapOID.size() - 1));
356           OID enterprise = new OID(trapOID);
357           enterprise.trim(2);
358           targetV1.setEnterprise(enterprise);
359         }
360         else if (trapOID.size() > 1) {
361           targetV1.setSpecificTrap(trapOID.get(trapOID.size() - 1));
362           OID enterprise = new OID(trapOID);
363           enterprise.trim(1);
364           targetV1.setEnterprise(enterprise);
365         }
366       }
367       else {
368         targetV1.setGenericTrap(genericID);
369         targetV1.setSpecificTrap(0);
370       }
371       target.addAll(source.toArray());
372       if (request.getCommandEvent().getPeerAddress() instanceof IpAddress) {
373         InetAddress JavaDoc agentAddress = ((IpAddress)
374            request.getCommandEvent().getPeerAddress()).getInetAddress();
375         targetV1.setAgentAddress(new IpAddress(agentAddress));
376       }
377       else {
378         targetV1.setAgentAddress(new IpAddress("0.0.0.0"));
379       }
380       targetV1.setTimestamp(sysUpTime.getValue());
381     }
382     else {
383       target.addAll(source.toArray());
384     }
385   }
386
387   protected boolean multipleForward(ProxyForwardRequest request) {
388     List matches = getMatches(request);
389     boolean allOK = true;
390     for (Iterator it = matches.iterator(); it.hasNext(); ) {
391       SnmpProxyRow item = (SnmpProxyRow) it.next();
392       OctetString outParam = item.getSnmpProxyMultipleTargetOut();
393       Set tags = SnmpTagList.getTags(outParam);
394       if (logger.isDebugEnabled()) {
395         logger.debug("Proxy multiple targets out with tags "+tags);
396       }
397       for (Iterator tagit = tags.iterator (); tagit.hasNext(); ) {
398         OctetString tag = (OctetString) tagit.next();
399         Collection targets = this.targetMIB.getTargetAddrRowsForTag(tag);
400         for (Iterator tit = targets.iterator(); tit.hasNext(); ) {
401           SnmpTargetAddrEntryRow targetRow =
402               (SnmpTargetAddrEntryRow) tit.next();
403           Target target = targetRow.getTarget(request.getContextEngineID(),
404                                               request.getContext());
405           if (target != null) {
406             try {
407               PDU reqPDU = request.getCommandEvent().getPDU();
408               PDU pdu = DefaultPDUFactory.createPDU(target, reqPDU.getType());
409               setScope(request, pdu);
410               proxyForwardTranslation(request, reqPDU, pdu);
411               ResponseEvent resp = session.send(pdu, target);
412               if (logger.isInfoEnabled()) {
413                 logger.info("Forwarded " + request.getCommandEvent() +
414                             " to target " + target + " with response " + resp);
415               }
416               if (request.getCommandEvent().getPDU().getType() == PDU.INFORM) {
417                 if ((resp.getResponse() == null) ||
418                     (resp.getResponse().getType() == PDU.REPORT) ||
419                     (resp.getResponse().getErrorStatus() != PDU.noError)) {
420                   allOK = false;
421                 }
422               }
423             }
424             catch (IOException ex) {
425               if (logger.isDebugEnabled()) {
426                 ex.printStackTrace();
427               }
428               logger.error("Failed to forward request " + request +
429                            " to target " + target);
430               allOK = false;
431             }
432           }
433           else {
434             if (logger.isDebugEnabled()) {
435               logger.debug("Parameters for target " + targetRow + " not found");
436             }
437           }
438         }
439       }
440     }
441     return allOK;
442   }
443
444   private void setScope(ProxyForwardRequest request, PDU pdu) {
445     if (pdu instanceof ScopedPDU) {
446       ScopedPDU scopedPDU = (ScopedPDU)pdu;
447       scopedPDU.setContextEngineID(request.getContextEngineID());
448       scopedPDU.setContextName(request.getContext());
449     }
450   }
451
452   public synchronized void addCounterListener(CounterListener l) {
453     if (counterListeners == null) {
454       counterListeners = new Vector(2);
455     }
456     counterListeners.add(l);
457   }
458
459   public synchronized void removeCounterListener(CounterListener l) {
460     if (counterListeners != null) {
461       counterListeners.remove(l);
462     }
463   }
464
465   protected void fireIncrementCounter(CounterEvent event) {
466     if (counterListeners != null) {
467       Vector listeners = counterListeners;
468       int count = listeners.size();
469       for (int i = 0; i < count; i++) {
470         ((CounterListener) listeners.elementAt(i)).incrementCounter(event);
471       }
472     }
473   }
474
475 }
476
Popular Tags