1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  package org.metricshub.snmp.client;
24  
25  import uk.co.westhawk.snmp.pdu.BlockPdu;
26  import uk.co.westhawk.snmp.stack.AsnObject;
27  import uk.co.westhawk.snmp.stack.AsnObjectId;
28  import uk.co.westhawk.snmp.stack.AsnOctets;
29  import uk.co.westhawk.snmp.stack.PduException;
30  import uk.co.westhawk.snmp.stack.SnmpConstants;
31  import uk.co.westhawk.snmp.stack.SnmpContext;
32  import uk.co.westhawk.snmp.stack.SnmpContextv2c;
33  import uk.co.westhawk.snmp.stack.SnmpContextv3;
34  import uk.co.westhawk.snmp.stack.SnmpContextv3Face;
35  import uk.co.westhawk.snmp.stack.varbind;
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.Collections;
40  import java.util.HashSet;
41  import java.util.List;
42  import java.util.Set;
43  
44  public class SnmpClient implements ISnmpClient {
45  
46  	
47  	public static final int SNMP_PORT = 161;
48  
49  	
50  	public static final int SNMP_V1 = 1;
51  	public static final int SNMP_V2C = 2;
52  	public static final int SNMP_V3 = 3;
53  	public static final String SNMP_AUTH_MD5 = "MD5";
54  	public static final String SNMP_AUTH_SHA = "SHA";
55  	public static final String SNMP_AUTH_SHA256 = "SHA256";
56  	public static final String SNMP_AUTH_SHA512 = "SHA512";
57  	public static final String SNMP_AUTH_SHA224 = "SHA224";
58  	public static final String SNMP_AUTH_SHA384 = "SHA384";
59  	public static final String SNMP_PRIVACY_DES = "DES";
60  	public static final String SNMP_PRIVACY_AES = "AES";
61  	public static final String SNMP_PRIVACY_AES192 = "AES192";
62  	public static final String SNMP_PRIVACY_AES256 = "AES256";
63  	public static final String SNMP_NONE = "None";
64  
65      public static final Set<String> SNMP_PRIVACY_PROTOCOLS = Collections.unmodifiableSet( new HashSet<>(
66      		Arrays.asList(SNMP_PRIVACY_DES, SNMP_PRIVACY_AES, SNMP_PRIVACY_AES192, SNMP_PRIVACY_AES256)));
67      
68      public static final Set<String> SNMP_AUTH_PROTOCOLS = Collections.unmodifiableSet( new HashSet<>(
69      		Arrays.asList(SNMP_AUTH_MD5, SNMP_AUTH_SHA, SNMP_AUTH_SHA256, SNMP_AUTH_SHA512, SNMP_AUTH_SHA224, SNMP_AUTH_SHA384)));
70      
71  	private SnmpContext contextv1 = null;
72  	private SnmpContextv2c contextv2c = null;
73  	private SnmpContextv3 contextv3 = null;
74  	private BlockPdu pdu;
75  	private String host;
76  	private int port;
77  	private String community;
78  	private int snmpVersion;
79  	private String authUsername;
80  	private String authType;
81  	private String authPassword;
82  	private String privacyType;
83  	private String privacyPassword;
84  	private int[] retryIntervals;
85  	private String contextName;
86  	private byte[] contextEngineID;
87  	public static final String SOCKET_TYPE = "Standard";
88  
89  	
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 	public SnmpClient(String host, int port, int version, int[] retryIntervals,
118 			String community,
119 			String authType, String authUsername, String authPassword,
120 			String privacyType, String privacyPassword,
121 			String contextName, byte[] contextID) throws IOException {
122 		
123 		validate(version, authType, privacyType);
124 
125 		
126 		this.host = host;
127 		this.port = port;
128 		this.snmpVersion = version;
129 		this.retryIntervals = retryIntervals;
130 		this.community = community;
131 		this.authType = authType;
132 		this.authUsername = authUsername;
133 		this.authPassword = authPassword;
134 		this.privacyType = privacyType;
135 		this.privacyPassword = privacyPassword;
136 		this.contextName = contextName;
137 		this.contextEngineID = contextID;
138 
139 		
140 		initialize();
141 	}
142 
143 	
144 
145 
146 
147 
148 
149 
150 
151 	private void validate(int version, String authType, String privacyType) {
152 
153 		
154 		if (version == SNMP_V3) {
155 			if (authType != null) {
156 				if (!authType.isEmpty()) {
157 					if (! SNMP_AUTH_PROTOCOLS.contains(authType)) {
158 						throw new IllegalArgumentException("Invalid authentication method '" + authType + "'." +
159 								" (Valid options are: '" + SNMP_AUTH_MD5
160 								+ "', '" + SNMP_AUTH_SHA
161 								+ "', '" + SNMP_AUTH_SHA256
162 								+ "', '" + SNMP_AUTH_SHA512
163 								+ "', '" + SNMP_AUTH_SHA224
164 								+ "', '" + SNMP_AUTH_SHA384
165 								+ "', or empty)");
166 					}
167 				}
168 			}
169 
170 			if (privacyType != null) {
171 				if (!privacyType.isEmpty()) {
172 					if (! SNMP_PRIVACY_PROTOCOLS.contains(privacyType)) {
173 						throw new IllegalArgumentException(
174 								"Invalid privacy method '" + privacyType + "'." + " (Valid options are:'" + SNMP_PRIVACY_DES
175 								+ "', '" + SNMP_PRIVACY_AES + "', '" + SNMP_PRIVACY_AES192 + "', '" + SNMP_PRIVACY_AES256  + "', or empty)");
176 					}
177 				}
178 			}
179 		}
180 	}
181 
182 	
183 
184 
185 
186 
187 
188 
189 
190 
191 
192 	private void initialize() throws IOException {
193 
194 		
195 		if (snmpVersion == SNMP_V2C) {
196 			contextv2c = new SnmpContextv2c(host, port, null, SOCKET_TYPE);
197 			contextv2c.setCommunity(community);
198 		}
199 
200 		
201 		else if (snmpVersion == SNMP_V3) {
202 			int authProtocolCode = 0;
203 			int privacyProtocolCode = 0;
204 			boolean authenticate = false;
205 			boolean privacy = false;
206 
207 			
208 			if (contextEngineID == null) {
209 				contextEngineID = new byte[0];
210 			}
211 			if (contextName == null) {
212 				contextName = "";
213 			}
214 
215 			
216 			if (authUsername == null) {
217 				authUsername = "";
218 			}
219 
220 			
221 			if (authType == null || authUsername == null || authPassword == null) {
222 				authenticate = false;
223 				authProtocolCode = SnmpContextv3Face.NO_AUTH_PROTOCOL;
224 				authPassword = "";
225 			} else if (authType.isEmpty() || authUsername.isEmpty() || authPassword.isEmpty()) {
226 				authenticate = false;
227 				authProtocolCode = SnmpContextv3Face.NO_AUTH_PROTOCOL;
228 				authPassword = "";
229 			} else if (authType.equals(SNMP_AUTH_MD5)) {
230 				authenticate = true;
231 				authProtocolCode = SnmpContextv3Face.MD5_PROTOCOL;
232 			} else if (authType.equals(SNMP_AUTH_SHA)) {
233 				authenticate = true;
234 				authProtocolCode = SnmpContextv3Face.SHA1_PROTOCOL;
235 			} else if (authType.equals(SNMP_AUTH_SHA256)) {
236 				authenticate = true;
237 				authProtocolCode = SnmpContextv3Face.SHA256_PROTOCOL;
238 			} else if (authType.equals(SNMP_AUTH_SHA512)) {
239 				authenticate = true;
240 				authProtocolCode = SnmpContextv3Face.SHA512_PROTOCOL;
241 			} else if (authType.equals(SNMP_AUTH_SHA224)) {
242 				authenticate = true;
243 				authProtocolCode = SnmpContextv3Face.SHA224_PROTOCOL;
244 
245 			} else if (authType.equals(SNMP_AUTH_SHA384)) {
246 				authenticate = true;
247 				authProtocolCode = SnmpContextv3Face.SHA384_PROTOCOL;
248 			}
249 
250 			
251 			if (privacyType == null || privacyPassword == null) {
252 				privacy = false;
253 			} else if (privacyType.isEmpty() || privacyPassword.isEmpty()) {
254 				privacy = false;
255 			} else if (privacyType.equals(SNMP_PRIVACY_DES)) {
256 				privacy = true;
257 				privacyProtocolCode = SnmpContextv3Face.DES_ENCRYPT;
258 			} else if (privacyType.equals(SNMP_PRIVACY_AES)) {
259 				privacy = true;
260 				privacyProtocolCode = SnmpContextv3Face.AES_ENCRYPT;
261 			} else if (privacyType.equals(SNMP_PRIVACY_AES192)) {
262 			    privacy = true;
263 			    privacyProtocolCode = SnmpContextv3Face.AES192_ENCRYPT;
264 			} else if (privacyType.equals(SNMP_PRIVACY_AES256)) {
265 			    privacy = true;
266 			    privacyProtocolCode = SnmpContextv3Face.AES256_ENCRYPT;
267 			}
268 			
269 			if (privacy && !authenticate) {
270 				throw new IllegalStateException("Authentication is required for privacy to be enforced");
271 			}
272 
273 			
274 			contextv3 = new SnmpContextv3(host, port, SOCKET_TYPE);
275 			contextv3.setContextEngineId(contextEngineID);
276 			contextv3.setContextName(contextName);
277 			contextv3.setUserName(authUsername);
278 			contextv3.setUseAuthentication(authenticate);
279 			if (authenticate) {
280 				contextv3.setUserAuthenticationPassword(authPassword);
281 				contextv3.setAuthenticationProtocol(authProtocolCode);
282 				contextv3.setUsePrivacy(privacy);
283 				if (privacy) {
284 					contextv3.setPrivacyProtocol(privacyProtocolCode);
285 					contextv3.setUserPrivacyPassword(privacyPassword);
286 				}
287 			}
288 		}
289 
290 		
291 		else {
292 			contextv1 = new SnmpContext(host, port, SOCKET_TYPE);
293 			contextv1.setCommunity(community);
294 		}
295 
296 		
297 		
298 		AsnOctets.setHexPrefix("");
299 
300 		
301 
302 	}
303 
304 	
305 
306 
307 
308 	@Override
309 	public void freeResources() {
310 		if (contextv1 != null) {
311 			contextv1.destroy();
312 			contextv1 = null;
313 		}
314 		if (contextv2c != null) {
315 			contextv2c.destroy();
316 			contextv2c = null;
317 		}
318 		if (contextv3 != null) {
319 			contextv3.destroy();
320 			contextv3 = null;
321 		}
322 
323 		if (pdu != null) {
324 			pdu = null;
325 		}
326 	}
327 
328 	
329 
330 
331 
332 
333 
334 	private void createPdu() {
335 		
336 		if (snmpVersion == SNMP_V2C) {
337 			pdu = new BlockPdu(contextv2c);
338 		} else if (snmpVersion == SNMP_V3) {
339 			pdu = new BlockPdu(contextv3);
340 		} else {
341 			pdu = new BlockPdu(contextv1);
342 		}
343 
344 		
345 		if (retryIntervals != null) {
346 			pdu.setRetryIntervals(retryIntervals);
347 		}
348 	}
349 
350 	
351 
352 
353 
354 
355 
356 
357 	public String get(String oid) throws Exception {
358 		createPdu();
359 		pdu.setPduType(BlockPdu.GET);
360 		pdu.addOid(oid);
361 		return sendRequest().value;
362 	}
363 
364 	
365 
366 
367 
368 
369 
370 
371 
372 
373 	public String getWithDetails(String oid) throws Exception {
374 		createPdu();
375 		pdu.setPduType(BlockPdu.GET);
376 		pdu.addOid(oid);
377 		SnmpResult result = sendRequest();
378 		return result.oid + "\t" + result.type + "\t" + result.value;
379 	}
380 
381 	
382 
383 
384 
385 
386 
387 
388 
389 	public String getNext(String oid) throws Exception {
390 		createPdu();
391 		pdu.setPduType(BlockPdu.GETNEXT);
392 		pdu.addOid(oid);
393 		SnmpResult result = sendRequest();
394 		return result.oid + "\t" + result.type + "\t" + result.value;
395 	}
396 
397 	
398 
399 
400 
401 
402 
403 
404 
405 
406 
407 	public String walk(String oid) throws Exception {
408 
409 		StringBuilder walkResult = new StringBuilder();
410 		String currentOID;
411 		SnmpResult getNextResult;
412 
413 		
414 		if (oid == null) {
415 			throw new IllegalArgumentException("Invalid SNMP Walk OID: null");
416 		}
417 		if (oid.length() < 3) {
418 			throw new IllegalArgumentException("Invalid SNMP Walk OID: \"" + oid + "\"");
419 		}
420 
421 		
422 		
423 		
424 		
425 		
426 		
427 		
428 		
429 		
430 		
431 		
432 		getNext(oid);
433 
434 		currentOID = oid;
435 		do {
436 			createPdu();
437 			pdu.setPduType(BlockPdu.GETNEXT);
438 			pdu.addOid(currentOID);
439 			try {
440 				getNextResult = sendRequest();
441 			} catch (Exception e) {
442 				
443 				break;
444 			}
445 
446 			currentOID = getNextResult.oid;
447 			if (!currentOID.startsWith(oid)) {
448 				
449 				break;
450 			}
451 
452 			
453 			walkResult.append(currentOID + "\t" + getNextResult.type + "\t" + getNextResult.value + "\n");
454 
455 		} while (walkResult.length() < 10 * 1048576); 
456 														
457 
458 		
459 		int resultLength = walkResult.length();
460 		if (resultLength > 0) {
461 			return walkResult.substring(0, resultLength - 1);
462 		}
463 
464 		
465 		return "";
466 	}
467 
468 	
469 
470 
471 
472 
473 
474 
475 
476 
477 
478 	public List<List<String>> table(String rootOID, String[] selectColumnArray) throws Exception {
479 
480 		
481 		if (rootOID == null) {
482 			throw new IllegalArgumentException("Invalid SNMP Table OID: null");
483 		}
484 		if (rootOID.length() < 3) {
485 			throw new IllegalArgumentException("Invalid SNMP Table OID: \"" + rootOID + "\"");
486 		}
487 		if (selectColumnArray == null) {
488 			throw new IllegalArgumentException("Invalid SNMP Table column numbers: null");
489 		}
490 		if (selectColumnArray.length < 1) {
491 			throw new IllegalArgumentException("Invalid SNMP Table column numbers: none");
492 		}
493 
494 		
495 		
496 		
497 		createPdu();
498 		pdu.setPduType(BlockPdu.GETNEXT);
499 		pdu.addOid(rootOID);
500 		String firstValueOid = sendRequest().oid;
501 		if (firstValueOid.isEmpty() || !firstValueOid.startsWith(rootOID)) {
502 			
503 			return new ArrayList<>();
504 		}
505 
506 		int tempIndex = firstValueOid.indexOf(".", rootOID.length() + 2);
507 		if (tempIndex < 0) {
508 			
509 			
510 			return new ArrayList<>();
511 		}
512 		String firstColumnOid = firstValueOid.substring(0, tempIndex);
513 		int firstColumnOidLength = firstColumnOid.length();
514 
515 		
516 		
517 		ArrayList<String> IDArray = new ArrayList<String>(0);
518 		String currentOID = firstColumnOid;
519 		SnmpResult getNextResult;
520 		do {
521 			
522 			createPdu();
523 			pdu.setPduType(BlockPdu.GETNEXT);
524 			pdu.addOid(currentOID);
525 			getNextResult = sendRequest();
526 
527 			currentOID = getNextResult.oid;
528 
529 			
530 			if (!currentOID.startsWith(firstColumnOid)) {
531 				break;
532 			}
533 
534 			
535 			
536 			IDArray.add(currentOID.substring(firstColumnOidLength + 1));
537 
538 		} while (IDArray.size() < 10000); 
539 
540 		
541 		List<List<String>> tableResult = new ArrayList<>();
542 		for (String ID : IDArray) {
543 			
544 			List<String> row = new ArrayList<>();
545 			for (String column : selectColumnArray) {
546 				
547 
548 				
549 				if (column.equals("ID")) {
550 					row.add(ID);
551 				} else {
552 					
553 					try {
554 						row.add(get(rootOID + "." + column + "." + ID));
555 					} catch (Exception e) {
556 						row.add("");
557 					}
558 				}
559 			}
560 			tableResult.add(row);
561 		}
562 
563 		
564 		return tableResult;
565 	}
566 
567 	
568 
569 
570 
571 
572 
573 
574 
575 
576 
577 
578 
579 
580 	private SnmpResult sendRequest() throws PduException, IOException, Exception {
581 
582 		
583 		SnmpResult result = new SnmpResult();
584 
585 		
586 		varbind var = pdu.getResponseVariableBinding();
587 
588 		
589 		AsnObjectId oid = var.getOid();
590 		AsnObject value = var.getValue();
591 
592 		
593 		
594 		byte valueType = value.getRespType();
595 		if (valueType == SnmpConstants.SNMP_VAR_NOSUCHOBJECT ||
596 				valueType == SnmpConstants.SNMP_VAR_NOSUCHINSTANCE ||
597 				valueType == SnmpConstants.SNMP_VAR_ENDOFMIBVIEW) {
598 			throw new Exception(value.getRespTypeString());
599 		}
600 
601 		
602 		else if (valueType == SnmpConstants.ASN_NULL) {
603 			result.oid = oid.toString();
604 			result.type = "null";
605 		}
606 
607 		
608 		
609 		
610 		
611 		else if (valueType == SnmpConstants.ASN_OCTET_STR) {
612 
613 			result.oid = oid.toString();
614 			result.type = "ASN_OCTET_STR";
615 
616 			
617 			AsnOctets octetStringValue = (AsnOctets) value;
618 
619 			
620 			
621 			
622 			
623 			
624 			
625 			String octetStringValuetoString = octetStringValue.toString();
626 
627 			
628 			
629 			String octetStringValuetoHex = octetStringValue.toHex().replace(':', ' ');
630 
631 			
632 			
633 			
634 			
635 			
636 			
637 			
638 			
639 			
640 			
641 			
642 
643 			
644 			
645 			if (octetStringValuetoString.isEmpty() && octetStringValue.getBytes().length > 0) {
646 				result.value = octetStringValuetoHex;
647 			} else if (octetStringValuetoString.length() == octetStringValuetoHex.length()) {
648 				result.value = octetStringValuetoHex;
649 			} else {
650 				result.value = octetStringValuetoString;
651 			}
652 		}
653 
654 		
655 		else {
656 			result.oid = oid.toString();
657 			result.type = value.getRespTypeString();
658 			result.value = value.toString();
659 		}
660 
661 		return result;
662 
663 	} 
664 
665 }