View Javadoc

1   /**
2    * This file is part of GoldenGate Project (named also GoldenGate or GG).
3    * 
4    * Copyright 2009, Frederic Bregier, and individual contributors by the @author
5    * tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    * 
8    * All GoldenGate Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General private License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   * 
13   * GoldenGate is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General private License for more details.
16   * 
17   * You should have received a copy of the GNU General private License along with
18   * GoldenGate . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package goldengate.snmp;
21  
22  import java.io.File;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.dom4j.Document;
28  import org.dom4j.DocumentException;
29  import org.dom4j.io.SAXReader;
30  import org.snmp4j.agent.mo.snmp.StorageType;
31  import org.snmp4j.agent.mo.snmp.TransportDomains;
32  import org.snmp4j.security.AuthMD5;
33  import org.snmp4j.security.AuthSHA;
34  import org.snmp4j.security.Priv3DES;
35  import org.snmp4j.security.PrivAES128;
36  import org.snmp4j.security.PrivAES192;
37  import org.snmp4j.security.PrivAES256;
38  import org.snmp4j.security.PrivDES;
39  import org.snmp4j.security.UsmUser;
40  import org.snmp4j.smi.OID;
41  import org.snmp4j.smi.OctetString;
42  import org.snmp4j.smi.TcpAddress;
43  import org.snmp4j.smi.TransportIpAddress;
44  import org.snmp4j.smi.UdpAddress;
45  
46  import goldengate.common.logging.GgInternalLogger;
47  import goldengate.common.logging.GgInternalLoggerFactory;
48  import goldengate.common.xml.XmlDecl;
49  import goldengate.common.xml.XmlHash;
50  import goldengate.common.xml.XmlType;
51  import goldengate.common.xml.XmlUtil;
52  import goldengate.common.xml.XmlValue;
53  
54  /**
55   * SnmpConfiguration class from XML file
56   * 
57   * @author Frederic Bregier
58   * 
59   */
60  public class SnmpConfiguration {
61      /**
62       * Internal Logger
63       */
64      private static final GgInternalLogger logger = GgInternalLoggerFactory
65              .getLogger(SnmpConfiguration.class);
66  
67      private static final String SNMP_ROOT = "/snmpconfig/";
68  
69      private static final String SNMP_CONFIG = "config";
70  
71      private static final String SNMP_LOCAL_ADDRESS = "localaddress";
72  
73      private static final String SNMP_NBTHREAD = "nbthread";
74  
75      private static final String SNMP_FILTERED = "filtered";
76  
77      private static final String SNMP_USETRAP = "usetrap";
78  
79      private static final String SNMP_TRAPLEVEL = "trapinformlevel";
80  
81      private static final XmlDecl[] configConfigDecls = {
82      new XmlDecl(SNMP_LOCAL_ADDRESS, XmlType.STRING, SNMP_LOCAL_ADDRESS, true),
83              new XmlDecl(XmlType.INTEGER, SNMP_NBTHREAD),
84              new XmlDecl(XmlType.BOOLEAN, SNMP_FILTERED),
85              new XmlDecl(XmlType.BOOLEAN, SNMP_USETRAP),
86              new XmlDecl(XmlType.INTEGER, SNMP_TRAPLEVEL) };
87  
88      private static final String SNMP_TARGETS = "targets";
89  
90      private static final String SNMP_TARGET = "target";
91  
92      /**
93       * Static String
94       */
95      public static final String NOTIFY = "notify";
96  
97      /**
98       * Static String
99       */
100     public static final String V3NOTIFY = "v3notify";
101 
102     /**
103      * Static String
104      */
105     public static final String V2C = "v2c";
106 
107     /*
108      * addTargetAddress(org.snmp4j.smi.OctetString name, org.snmp4j.smi.OID
109      * transportDomain, org.snmp4j.smi.OctetString address, int timeout, int
110      * retries, org.snmp4j.smi.OctetString tagList, "notify"
111      * org.snmp4j.smi.OctetString params, "v3notify"/"v2c" int storageType)
112      * permenant
113      */
114     private static final String SNMP_TARGET_NAME = "name";
115 
116     private static final String SNMP_TARGET_DOMAIN = "domain";
117 
118     private static final String SNMP_TARGET_ADDRESS = "address";
119 
120     private static final String SNMP_TARGET_TIMEOUT = "timeout";
121 
122     private static final String SNMP_TARGET_RETRIES = "retries";
123 
124     private static final String SNMP_TARGET_ISV2 = "isv2";
125 
126     private static final XmlDecl[] configTargetDecls = {
127             new XmlDecl(XmlType.STRING, SNMP_TARGET_NAME),
128             new XmlDecl(XmlType.STRING, SNMP_TARGET_DOMAIN),
129             new XmlDecl(XmlType.STRING, SNMP_TARGET_ADDRESS),
130             new XmlDecl(XmlType.INTEGER, SNMP_TARGET_TIMEOUT),
131             new XmlDecl(XmlType.INTEGER, SNMP_TARGET_RETRIES),
132             new XmlDecl(XmlType.BOOLEAN, SNMP_TARGET_ISV2) };
133 
134     /*
135      * org.snmp4j.security.UsmUser.UsmUser(OctetString securityName, OID
136      * authenticationProtocol, OctetString authenticationPassphrase, OID
137      * privacyProtocol, OctetString privacyPassphrase)
138      * 
139      * Creates a USM user.
140      * 
141      * Parameters: 
142      * 
143      * -securityName the security name of the user (typically the user name). 
144      * 
145      * -authenticationProtocol the authentication protcol ID to be
146      * associated with this user. If set to null, this user only supports
147      * unauthenticated messages. 
148      * 
149      * -authenticationPassphrase the authentication
150      * passphrase. If not null, authenticationProtocol must also be not null.
151      * RFC3414 §11.2 requires passphrases to have a minimum length of 8 bytes.
152      * If the length of authenticationPassphrase is less than 8 bytes an
153      * IllegalArgumentException is thrown. 
154      * 
155      * -privacyProtocol the privacy protcol
156      * ID to be associated with this user. If set to null, this user only
157      * supports unencrypted messages. 
158      * 
159      * -privacyPassphrase the privacy passphrase.
160      * If not null, privacyProtocol must also be not null. RFC3414 §11.2
161      * requires passphrases to have a minimum length of 8 bytes. If the length
162      * of authenticationPassphrase is less than 8 bytes an
163      * IllegalArgumentException is thrown.
164      */
165     private static final String SNMP_SECURITIES = "securities";
166 
167     private static final String SNMP_SECURITY = "security";
168 
169     private static final String SNMP_SECURITY_NAME = "securityname";
170 
171     private static final String SNMP_SECURITY_AUTH_PROTOCOL = "securityauthprotocol";
172 
173     private static final String SNMP_SECURITY_AUTH_PASSPHRASE = "securityauthpass";
174 
175     private static final String SNMP_SECURITY_PRIV_PROTOCOL = "securityprivprotocol";
176 
177     private static final String SNMP_SECURITY_PRIV_PASSPHRASE = "securityprivpass";
178 
179     private static final XmlDecl[] configSecurityDecls = {
180             new XmlDecl(XmlType.STRING, SNMP_SECURITY_NAME),
181             new XmlDecl(XmlType.STRING, SNMP_SECURITY_AUTH_PROTOCOL),
182             new XmlDecl(XmlType.STRING, SNMP_SECURITY_AUTH_PASSPHRASE),
183             new XmlDecl(XmlType.STRING, SNMP_SECURITY_PRIV_PROTOCOL),
184             new XmlDecl(XmlType.STRING, SNMP_SECURITY_PRIV_PASSPHRASE) };
185 
186     private static final XmlDecl[] configSNMP = {
187             new XmlDecl(SNMP_CONFIG, XmlType.XVAL, SNMP_ROOT + SNMP_CONFIG,
188                     configConfigDecls, false),
189             new XmlDecl(SNMP_SECURITY, XmlType.XVAL, SNMP_ROOT +
190                     SNMP_SECURITIES + "/" + SNMP_SECURITY, configSecurityDecls,
191                     true),
192             new XmlDecl(SNMP_TARGET, XmlType.XVAL, SNMP_ROOT + SNMP_TARGETS +
193                     "/" + SNMP_TARGET, configTargetDecls, true) };
194 
195     private static XmlValue[] configuration = null;
196 
197     private static XmlHash hashConfig = null;
198     /**
199      * Address from the configuration for the SNMP Agent listening port
200      */
201     public static String[] address = null;
202     /**
203      * Number of threads to use in SNMP agent
204      */
205     public static int nbThread = 4;
206     /**
207      * Do we filter on Targets for SNMP requests
208      */
209     public static boolean isFilterAccessEnabled = false;
210     /**
211      * Do we are using Trap or Inform
212      */
213     public static boolean isUsingTrap = true;
214     /**
215      * Level for Trap/Inform from 0 to 4
216      */
217     public static int trapLevel = 0;
218     /**
219      * Default address: all in UDP port 161
220      */
221     public static final String DEFAULTADDRESS = "udp:0.0.0.0/161";
222 
223     /**
224      * 
225      * 
226      * @return True if the configuration successfully load
227      */
228     private static boolean loadConfig() {
229         XmlValue value = hashConfig.get(SNMP_LOCAL_ADDRESS);
230         @SuppressWarnings("unchecked")
231         List<String> values = (List<String>) value.getList();
232         int length = values.size();
233         if (length == 0) {
234             address = new String[] {
235                 DEFAULTADDRESS };
236         } else {
237             address = new String[length];
238             int nb = 0;
239             address = values.toArray(address);
240             String[] tmp = new String[length];
241             for (int j = 0; j < length; j ++) {
242                 if (address[j] != null && (!address[j].trim().isEmpty())) {
243                     tmp[nb] = address[j];
244                     nb ++;
245                 }
246             }
247             if (nb == 0) {
248                 address = new String[] {
249                     DEFAULTADDRESS };
250             } else if (nb < length) {
251                 // less addresses than intended
252                 address = new String[nb];
253                 System.arraycopy(tmp, 0, address, 0, nb);
254                 /*for (int i = 0; i < nb; i ++) {
255                     address[i] = tmp[i];
256                 }*/
257             }
258         }
259         value = hashConfig.get(SNMP_NBTHREAD);
260         if (value != null && (!value.isEmpty())) {
261             nbThread = value.getInteger();
262             if (nbThread <= 0) nbThread = 4;
263         }
264         value = hashConfig.get(SNMP_FILTERED);
265         if (value != null && (!value.isEmpty())) {
266             isFilterAccessEnabled = value.getBoolean();
267         }
268         value = hashConfig.get(SNMP_USETRAP);
269         if (value != null && (!value.isEmpty())) {
270             isUsingTrap = value.getBoolean();
271         }
272         value = hashConfig.get(SNMP_TRAPLEVEL);
273         if (value != null && (!value.isEmpty())) {
274             trapLevel = value.getInteger();
275         }
276         return true;
277     }
278     /**
279      * List of all UsmUser
280      */
281     public static final List<UsmUser> listUsmUser = new ArrayList<UsmUser>();
282     /**
283      * Protocols for Security
284      * @author Frederic Bregier
285      *
286      */
287     public static enum SecurityProtocolList {
288         SHA(AuthSHA.ID), MD5(AuthMD5.ID);
289 
290         public OID oid;
291 
292         private SecurityProtocolList(OID oid) {
293             this.oid = oid;
294         }
295     }
296     /**
297      * Protocol for Privacy
298      * @author Frederic Bregier
299      *
300      */
301     public static enum PrivacyProtocolList {
302         P3DES(Priv3DES.ID),
303         PAES128(PrivAES128.ID),
304         PAES192(PrivAES192.ID),
305         PAES256(PrivAES256.ID),
306         PDES(PrivDES.ID);
307 
308         public OID oid;
309 
310         private PrivacyProtocolList(OID oid) {
311             this.oid = oid;
312         }
313     }
314 
315     /**
316      * 
317      new XmlDecl(XmlType.STRING, SNMP_SECURITY_NAME), new
318      * XmlDecl(XmlType.STRING, SNMP_SECURITY_AUTH_PROTOCOL), new
319      * XmlDecl(XmlType.STRING, SNMP_SECURITY_AUTH_PASSPHRASE), new
320      * XmlDecl(XmlType.STRING, SNMP_SECURITY_PRIV_PROTOCOL), new
321      * XmlDecl(XmlType.STRING, SNMP_SECURITY_PRIV_PASSPHRASE)
322      * 
323      * 
324      * @return True if load successfully
325      */
326     private static boolean loadSecurity() {
327         String securityName = null;
328         String securityProtocol = null;
329         String securityPassphrase = null;
330         String securityPrivProtocol = null;
331         String securityPrivPassphrase = null;
332         XmlValue value = hashConfig.get(SNMP_SECURITY);
333         @SuppressWarnings("unchecked")
334         List<XmlValue[]> list = (List<XmlValue[]>) value.getList();
335         Iterator<XmlValue[]> iterator = list.iterator();
336         while (iterator.hasNext()) {
337             securityName = null;
338             securityProtocol = null;
339             securityPassphrase = null;
340             securityPrivProtocol = null;
341             securityPrivPassphrase = null;
342             XmlValue[] subvalues = iterator.next();
343             XmlHash subHash = new XmlHash(subvalues);
344             value = subHash.get(SNMP_SECURITY_NAME);
345             if (value == null || (value.isEmpty())) {
346                 logger.warn("No Security Name found");
347                 continue;
348             }
349             securityName = value.getString();
350             value = subHash.get(SNMP_SECURITY_AUTH_PROTOCOL);
351             SecurityProtocolList secprot = null;
352             if (value != null && (!value.isEmpty())) {
353                 securityProtocol = value.getString();
354                 try {
355                     secprot = SecurityProtocolList.valueOf(securityProtocol);
356                 } catch (IllegalArgumentException e) {
357                     logger.warn("No Security Protocol found for " +
358                             securityName);
359                     continue;
360                 }
361                 value = subHash.get(SNMP_SECURITY_AUTH_PASSPHRASE);
362                 if (value == null || (value.isEmpty())) {
363                     // not allowed
364                     securityProtocol = null;
365                 }
366                 securityPassphrase = value.getString();
367             }
368             value = subHash.get(SNMP_SECURITY_PRIV_PROTOCOL);
369             PrivacyProtocolList privprot = null;
370             if (value != null && (!value.isEmpty())) {
371                 securityPrivProtocol = value.getString();
372                 try {
373                     privprot = PrivacyProtocolList
374                             .valueOf(securityPrivProtocol);
375                 } catch (IllegalArgumentException e) {
376                     logger.warn("No Security Private Protocol found for " +
377                             securityName);
378                     continue;
379                 }
380                 value = subHash.get(SNMP_SECURITY_PRIV_PASSPHRASE);
381                 if (value == null || (value.isEmpty())) {
382                     // not allowed
383                     securityPrivProtocol = null;
384                 }
385                 securityPrivPassphrase = value.getString();
386             }
387             UsmUser usm = new UsmUser(new OctetString(securityName),
388                     secprot == null? null : secprot.oid, secprot == null? null
389                             : new OctetString(securityPassphrase),
390                     privprot == null? null : privprot.oid,
391                     privprot == null? null : new OctetString(
392                             securityPrivPassphrase));
393             listUsmUser.add(usm);
394         }
395         return true;
396     }
397 
398     private static enum TransportDomain {
399         UdpIpv4(TransportDomains.transportDomainUdpIpv4), UdpIpv6(
400                 TransportDomains.transportDomainUdpIpv6), UdpIpv4z(
401                 TransportDomains.transportDomainUdpIpv4z), UdpIpv6z(
402                 TransportDomains.transportDomainUdpIpv6z), TcpIpv4(
403                 TransportDomains.transportDomainTcpIpv4), TcpIpv6(
404                 TransportDomains.transportDomainTcpIpv6), TcpIpv4z(
405                 TransportDomains.transportDomainTcpIpv4z), TcpIpv6z(
406                 TransportDomains.transportDomainTcpIpv6z);
407 
408         public OID oid;
409 
410         private TransportDomain(OID oid) {
411             this.oid = oid;
412         }
413     }
414     /**
415      * Target entry
416      * @author Frederic Bregier
417      *
418      */
419     public static class TargetElement {
420         public OctetString name;
421 
422         public OID transportDomain;
423 
424         public OctetString address;
425 
426         public int timeout;
427 
428         public int retries;
429 
430         public OctetString tagList;
431 
432         public OctetString params;
433 
434         public int storageType;
435 
436         /**
437          * @param name
438          * @param transportDomain
439          * @param address
440          * @param timeout
441          * @param retries
442          * @param tagList
443          * @param params
444          * @param storageType
445          */
446         private TargetElement(OctetString name, OID transportDomain,
447                 OctetString address, int timeout, int retries,
448                 OctetString tagList, OctetString params, int storageType) {
449             this.name = name;
450             this.transportDomain = transportDomain;
451             this.address = address;
452             this.timeout = timeout;
453             this.retries = retries;
454             this.tagList = tagList;
455             this.params = params;
456             this.storageType = storageType;
457         }
458 
459         public String toString() {
460             return "Name: " + name + " TD: " + transportDomain + " Add: " +
461                     address + " TO: " + timeout + " RT: " + retries + " TL: " +
462                     tagList + " PM: " + params + " ST: " + storageType;
463         }
464     }
465     /**
466      * List of Target Element
467      */
468     public static final List<TargetElement> listTargetElements = new ArrayList<SnmpConfiguration.TargetElement>();
469     /**
470      * Do we use SNMP V2c
471      */
472     public static boolean hasV2 = false;
473     /**
474      * Do we use SNMP V3
475      */
476     public static boolean hasV3 = false;
477 
478     /**
479      * 
480      new XmlDecl(XmlType.STRING, SNMP_TARGET_NAME), free name new
481      * XmlDecl(XmlType.STRING, SNMP_TARGET_DOMAIN), one of (Udp/Tcp)Ipv(4/6)[z]
482      * new XmlDecl(XmlType.STRING, SNMP_TARGET_ADDRESS), new
483      * XmlDecl(XmlType.INTEGER, SNMP_TARGET_TIMEOUT), new
484      * XmlDecl(XmlType.INTEGER, SNMP_TARGET_RETRIES), new
485      * XmlDecl(XmlType.BOOLEAN, SNMP_TARGET_ISV2) True => v2, else v3
486      * 
487      * new OctetString("notificationV2c"),
488      * TransportDomains.transportDomainUdpIpv4, new OctetString( new
489      * UdpAddress(toAddressV2).getValue()), 200, 1, new OctetString("notify"),
490      * new OctetString("v2c"), StorageType.permanent
491      * 
492      * new OctetString("notificationV3"),
493      * TransportDomains.transportDomainUdpIpv4, new OctetString( new
494      * UdpAddress(toAddressV3).getValue()), 200, 1, new OctetString("notify"),
495      * new OctetString("v3notify"), StorageType.permanent
496      * 
497      * @return True if successfully loaded
498      */
499     private static boolean loadTarget() {
500         String targetName;
501         String targetDomain;
502         OID oTargetDomain;
503         String targetAddress;
504         int targetTimeout;
505         int targetRetries;
506         String targetParams;
507         XmlValue value = hashConfig.get(SNMP_TARGET);
508         @SuppressWarnings("unchecked")
509         List<XmlValue[]> list = (List<XmlValue[]>) value.getList();
510         Iterator<XmlValue[]> iterator = list.iterator();
511         while (iterator.hasNext()) {
512             targetName = null;
513             targetDomain = null;
514             oTargetDomain = null;
515             targetAddress = null;
516             targetTimeout = 0;
517             targetRetries = 0;
518             targetParams = null;
519             XmlValue[] subvalues = iterator.next();
520             XmlHash subHash = new XmlHash(subvalues);
521             value = subHash.get(SNMP_TARGET_NAME);
522             if (value == null || (value.isEmpty())) {
523                 logger.warn("No Target Name found");
524                 continue;
525             }
526             targetName = value.getString();
527             value = subHash.get(SNMP_TARGET_DOMAIN);
528             if (value == null || (value.isEmpty())) {
529                 logger.warn("No Target Domain found for " + targetName);
530                 continue;
531             }
532             targetDomain = value.getString();
533             TransportDomain domain = null;
534             try {
535                 domain = TransportDomain.valueOf(targetDomain);
536                 oTargetDomain = domain.oid;
537             } catch (IllegalArgumentException e) {
538                 logger.warn("No Target Domain correctly found for " +
539                         targetName);
540                 continue;
541             }
542             value = subHash.get(SNMP_TARGET_ADDRESS);
543             if (value == null || (value.isEmpty())) {
544                 logger.warn("No Target Address found for " + targetName);
545                 continue;
546             }
547             targetAddress = value.getString();
548             TransportIpAddress address = null;
549             try {
550                 switch (domain) {
551                     case UdpIpv4:
552                     case UdpIpv6:
553                     case UdpIpv4z:
554                     case UdpIpv6z:
555                         address = new UdpAddress(targetAddress);
556                         break;
557                     case TcpIpv4:
558                     case TcpIpv6:
559                     case TcpIpv4z:
560                     case TcpIpv6z:
561                         address = new TcpAddress(targetAddress);
562                         break;
563                 }
564             } catch (IllegalArgumentException e) {
565                 logger.warn("No Correct Target Address found for " + targetName);
566                 continue;
567             }
568             logger.debug("Addr: {} {}", address.getClass(), targetAddress);
569             value = subHash.get(SNMP_TARGET_TIMEOUT);
570             if (value == null || (value.isEmpty())) {
571                 targetTimeout = 200;
572             }
573             targetTimeout = value.getInteger();
574             if (targetTimeout <= 100) {
575                 targetTimeout = 100;
576             }
577             value = subHash.get(SNMP_TARGET_RETRIES);
578             if (value == null || (value.isEmpty())) {
579                 targetRetries = 1;
580             }
581             targetRetries = value.getInteger();
582             if (targetRetries <= 0) targetRetries = 1;
583             value = subHash.get(SNMP_TARGET_ISV2);
584             boolean isV2 = true;
585             if (value == null || (value.isEmpty())) {
586                 isV2 = true;
587             } else {
588                 isV2 = value.getBoolean();
589             }
590             if (isV2) {
591                 hasV2 = true;
592                 targetParams = V2C;
593             } else {
594                 hasV3 = true;
595                 targetParams = V3NOTIFY;
596             }
597             TargetElement element = new TargetElement(new OctetString(
598                     targetName), oTargetDomain, new OctetString(
599                     address.getValue()), targetTimeout, targetRetries,
600                     new OctetString(NOTIFY), new OctetString(targetParams),
601                     StorageType.permanent);
602             listTargetElements.add(element);
603         }
604         return true;
605     }
606 
607     /**
608      * Initiate the configuration from the xml file for SNMP agent
609      * 
610      * @param file
611      * @return True if OK
612      */
613     public static boolean setConfigurationFromXml(File file) {
614         Document document = null;
615         // Open config file
616         try {
617             document = new SAXReader().read(file);
618         } catch (DocumentException e) {
619             logger.error(
620                     "Unable to read the XML Config file: " +
621                             file.getAbsolutePath(), e);
622             return false;
623         }
624         if (document == null) {
625             logger.error("Unable to read the XML Config file: " +
626                     file.getAbsolutePath());
627             return false;
628         }
629         configuration = XmlUtil.read(document, configSNMP);
630         hashConfig = new XmlHash(configuration);
631         address = new String[] {
632             DEFAULTADDRESS };
633         nbThread = 4;
634         listUsmUser.clear();
635         listTargetElements.clear();
636         try {
637             // Now read the configuration
638             if (!loadConfig()) return false;
639             if (!loadSecurity()) return false;
640             if (!loadTarget()) return false;
641         } finally {
642             hashConfig.clear();
643             hashConfig = null;
644             configuration = null;
645         }
646         return true;
647     }
648 }