Skip to content

Commit d61ff2a

Browse files
JiriOndrusekppalaga
authored andcommitted
Snmp: cover snmp v3 for POLL operation #4881
1 parent 22147af commit d61ff2a

File tree

6 files changed

+445
-105
lines changed

6 files changed

+445
-105
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.quarkus.component.snmp;
18+
19+
import java.util.List;
20+
21+
import org.apache.camel.Exchange;
22+
import org.apache.camel.Processor;
23+
import org.apache.camel.component.snmp.SnmpActionType;
24+
import org.apache.camel.component.snmp.SnmpEndpoint;
25+
import org.apache.camel.component.snmp.SnmpOIDPoller;
26+
import org.apache.camel.support.ScheduledPollConsumer;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
import org.snmp4j.CommunityTarget;
30+
import org.snmp4j.PDU;
31+
import org.snmp4j.ScopedPDU;
32+
import org.snmp4j.Snmp;
33+
import org.snmp4j.Target;
34+
import org.snmp4j.TransportMapping;
35+
import org.snmp4j.UserTarget;
36+
import org.snmp4j.event.ResponseEvent;
37+
import org.snmp4j.event.ResponseListener;
38+
import org.snmp4j.mp.MPv3;
39+
import org.snmp4j.mp.SnmpConstants;
40+
import org.snmp4j.security.AuthMD5;
41+
import org.snmp4j.security.AuthSHA;
42+
import org.snmp4j.security.Priv3DES;
43+
import org.snmp4j.security.PrivAES128;
44+
import org.snmp4j.security.PrivAES192;
45+
import org.snmp4j.security.PrivAES256;
46+
import org.snmp4j.security.PrivDES;
47+
import org.snmp4j.security.SecurityModels;
48+
import org.snmp4j.security.SecurityProtocols;
49+
import org.snmp4j.security.USM;
50+
import org.snmp4j.security.UsmUser;
51+
import org.snmp4j.smi.Address;
52+
import org.snmp4j.smi.GenericAddress;
53+
import org.snmp4j.smi.OID;
54+
import org.snmp4j.smi.OctetString;
55+
import org.snmp4j.smi.VariableBinding;
56+
import org.snmp4j.transport.DefaultTcpTransportMapping;
57+
import org.snmp4j.transport.DefaultUdpTransportMapping;
58+
import org.snmp4j.util.DefaultPDUFactory;
59+
import org.snmp4j.util.TreeEvent;
60+
import org.snmp4j.util.TreeUtils;
61+
62+
/**
63+
* A copy of SnmpOIDPoller fromm Camel
64+
*/
65+
public class QuarkusSnmpOIDPoller extends ScheduledPollConsumer implements ResponseListener {
66+
67+
private static final Logger LOG = LoggerFactory.getLogger(SnmpOIDPoller.class);
68+
69+
private Address targetAddress;
70+
private TransportMapping<? extends Address> transport;
71+
private Snmp snmp;
72+
73+
private Target target;
74+
private PDU pdu;
75+
private SnmpEndpoint endpoint;
76+
77+
public QuarkusSnmpOIDPoller(SnmpEndpoint endpoint, Processor processor) {
78+
super(endpoint, processor);
79+
this.endpoint = endpoint;
80+
}
81+
82+
@Override
83+
protected void doStart() throws Exception {
84+
super.doStart();
85+
86+
this.targetAddress = GenericAddress.parse(this.endpoint.getAddress());
87+
88+
// either tcp or udp
89+
if ("tcp".equals(endpoint.getProtocol())) {
90+
this.transport = new DefaultTcpTransportMapping();
91+
} else if ("udp".equals(endpoint.getProtocol())) {
92+
this.transport = new DefaultUdpTransportMapping();
93+
} else {
94+
throw new IllegalArgumentException("Unknown protocol: " + endpoint.getProtocol());
95+
}
96+
97+
this.snmp = new Snmp(this.transport);
98+
99+
if (SnmpConstants.version3 == endpoint.getSnmpVersion()) {
100+
UserTarget userTarget = new UserTarget();
101+
102+
userTarget.setSecurityLevel(endpoint.getSecurityLevel());
103+
userTarget.setSecurityName(convertToOctetString(endpoint.getSecurityName()));
104+
userTarget.setAddress(targetAddress);
105+
userTarget.setRetries(endpoint.getRetries());
106+
userTarget.setTimeout(endpoint.getTimeout());
107+
userTarget.setVersion(endpoint.getSnmpVersion());
108+
109+
this.target = userTarget;
110+
111+
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
112+
SecurityModels.getInstance().addSecurityModel(usm);
113+
114+
OID authProtocol = convertAuthenticationProtocol(endpoint.getAuthenticationProtocol());
115+
116+
OctetString authPwd = convertToOctetString(endpoint.getAuthenticationPassphrase());
117+
118+
OID privProtocol = convertPrivacyProtocol(endpoint.getPrivacyProtocol());
119+
120+
OctetString privPwd = convertToOctetString(endpoint.getPrivacyPassphrase());
121+
122+
UsmUser user = new UsmUser(
123+
convertToOctetString(endpoint.getSecurityName()), authProtocol, authPwd, privProtocol, privPwd);
124+
125+
usm.addUser(convertToOctetString(endpoint.getSecurityName()), user);
126+
127+
ScopedPDU scopedPDU = new ScopedPDU();
128+
129+
if (endpoint.getSnmpContextEngineId() != null) {
130+
scopedPDU.setContextEngineID(new OctetString(endpoint.getSnmpContextEngineId()));
131+
}
132+
133+
if (endpoint.getSnmpContextName() != null) {
134+
scopedPDU.setContextName(new OctetString(endpoint.getSnmpContextName()));
135+
}
136+
137+
this.pdu = scopedPDU;
138+
} else {
139+
CommunityTarget communityTarget = new CommunityTarget();
140+
141+
communityTarget.setCommunity(convertToOctetString(endpoint.getSnmpCommunity()));
142+
communityTarget.setAddress(targetAddress);
143+
communityTarget.setRetries(endpoint.getRetries());
144+
communityTarget.setTimeout(endpoint.getTimeout());
145+
communityTarget.setVersion(endpoint.getSnmpVersion());
146+
147+
this.target = communityTarget;
148+
149+
this.pdu = new PDU();
150+
}
151+
152+
// listen to the transport
153+
if (LOG.isDebugEnabled()) {
154+
LOG.debug("Starting OID poller on {} using {} protocol", endpoint.getAddress(), endpoint.getProtocol());
155+
}
156+
this.transport.listen();
157+
if (LOG.isInfoEnabled()) {
158+
LOG.info("Started OID poller on {} using {} protocol", endpoint.getAddress(), endpoint.getProtocol());
159+
}
160+
}
161+
162+
@Override
163+
protected void doStop() throws Exception {
164+
// stop listening to the transport
165+
if (this.transport != null && this.transport.isListening()) {
166+
LOG.info("Stopping OID poller on {}", targetAddress);
167+
this.transport.close();
168+
LOG.info("Stopped OID poller on {}", targetAddress);
169+
}
170+
171+
super.doStop();
172+
}
173+
174+
@Override
175+
protected int poll() throws Exception {
176+
this.pdu.clear();
177+
178+
int type = this.getPduType(this.endpoint.getType());
179+
180+
this.pdu.setType(type);
181+
182+
if (!endpoint.isTreeList()) {
183+
// prepare the request items
184+
for (OID oid : this.endpoint.getOids()) {
185+
this.pdu.add(new VariableBinding(oid));
186+
}
187+
} else {
188+
TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory());
189+
for (OID oid : this.endpoint.getOids()) {
190+
List events = treeUtils.getSubtree(target, new OID(oid));
191+
for (Object eventObj : events) {
192+
TreeEvent event = (TreeEvent) eventObj;
193+
if (event == null) {
194+
LOG.warn("Event is null");
195+
continue;
196+
}
197+
if (event.isError()) {
198+
LOG.error("Error in event: {}", event.getErrorMessage());
199+
continue;
200+
}
201+
VariableBinding[] varBindings = event.getVariableBindings();
202+
if (varBindings == null || varBindings.length == 0) {
203+
continue;
204+
}
205+
for (VariableBinding varBinding : varBindings) {
206+
if (varBinding == null) {
207+
continue;
208+
}
209+
this.pdu.add(varBinding);
210+
}
211+
}
212+
}
213+
}
214+
215+
// send the request
216+
snmp.send(pdu, target, null, this);
217+
218+
return 1;
219+
}
220+
221+
@Override
222+
public void onResponse(ResponseEvent event) {
223+
// Always cancel async request when response has been received
224+
// otherwise a memory leak is created! Not canceling a request
225+
// immediately can be useful when sending a request to a broadcast address.
226+
((Snmp) event.getSource()).cancel(event.getRequest(), this);
227+
228+
// check for valid response
229+
if (event.getRequest() == null || event.getResponse() == null) {
230+
// ignore null requests/responses
231+
LOG.debug("Received invalid SNMP event. Request: {} / Response: {}", event.getRequest(), event.getResponse());
232+
return;
233+
}
234+
235+
PDU pdu = event.getResponse();
236+
processPDU(pdu);
237+
}
238+
239+
/**
240+
* processes the pdu message
241+
*
242+
* @param pdu the pdu
243+
*/
244+
public void processPDU(PDU pdu) {
245+
if (LOG.isDebugEnabled()) {
246+
LOG.debug("Received response event for {} : {}", this.endpoint.getAddress(), pdu);
247+
}
248+
Exchange exchange = endpoint.createExchange(pdu);
249+
try {
250+
getProcessor().process(exchange);
251+
} catch (Exception e) {
252+
getExceptionHandler().handleException(e);
253+
}
254+
}
255+
256+
/**
257+
* * @return Returns the target.
258+
*/
259+
public Target getTarget() {
260+
return this.target;
261+
}
262+
263+
/**
264+
* @param target The target to set.
265+
*/
266+
public void setTarget(Target target) {
267+
this.target = target;
268+
}
269+
270+
private OctetString convertToOctetString(String value) {
271+
if (value == null) {
272+
return null;
273+
}
274+
return new OctetString(value);
275+
}
276+
277+
private OID convertAuthenticationProtocol(String authenticationProtocol) {
278+
if (authenticationProtocol == null) {
279+
return null;
280+
}
281+
if ("MD5".equals(authenticationProtocol)) {
282+
return AuthMD5.ID;
283+
} else if ("SHA1".equals(authenticationProtocol)) {
284+
return AuthSHA.ID;
285+
} else {
286+
throw new IllegalArgumentException("Unknown authentication protocol: " + authenticationProtocol);
287+
}
288+
}
289+
290+
private OID convertPrivacyProtocol(String privacyProtocol) {
291+
if (privacyProtocol == null) {
292+
return null;
293+
}
294+
if ("DES".equals(privacyProtocol)) {
295+
return PrivDES.ID;
296+
} else if ("TRIDES".equals(privacyProtocol)) {
297+
return Priv3DES.ID;
298+
} else if ("AES128".equals(privacyProtocol)) {
299+
return PrivAES128.ID;
300+
} else if ("AES192".equals(privacyProtocol)) {
301+
return PrivAES192.ID;
302+
} else if ("AES256".equals(privacyProtocol)) {
303+
return PrivAES256.ID;
304+
} else {
305+
throw new IllegalArgumentException("Unknown privacy protocol: " + privacyProtocol);
306+
}
307+
}
308+
309+
private int getPduType(SnmpActionType type) {
310+
if (SnmpActionType.GET_NEXT == type) {
311+
return PDU.GETNEXT;
312+
} else {
313+
return PDU.GET;
314+
}
315+
}
316+
317+
}

Diff for: extensions-jvm/snmp/runtime/src/main/java/org/apache/camel/quarkus/component/snmp/SnmpRecorder.java

+18
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020

2121
import io.quarkus.runtime.RuntimeValue;
2222
import io.quarkus.runtime.annotations.Recorder;
23+
import org.apache.camel.Consumer;
2324
import org.apache.camel.Endpoint;
25+
import org.apache.camel.Processor;
2426
import org.apache.camel.Producer;
2527
import org.apache.camel.component.snmp.SnmpActionType;
2628
import org.apache.camel.component.snmp.SnmpComponent;
2729
import org.apache.camel.component.snmp.SnmpEndpoint;
30+
import org.apache.camel.component.snmp.SnmpTrapConsumer;
2831

2932
@Recorder
3033
public class SnmpRecorder {
@@ -67,5 +70,20 @@ public Producer createProducer() throws Exception {
6770
return new QuarkusSnmpProducer(this, getType());
6871
}
6972
}
73+
74+
@Override
75+
public Consumer createConsumer(Processor processor) throws Exception {
76+
if (getType() == SnmpActionType.TRAP) {
77+
SnmpTrapConsumer answer = new SnmpTrapConsumer(this, processor);
78+
// As the SnmpTrapConsumer is not a polling consumer we don't need to call the configureConsumer here.
79+
return answer;
80+
} else if (getType() == SnmpActionType.POLL) {
81+
QuarkusSnmpOIDPoller answer = new QuarkusSnmpOIDPoller(this, processor);
82+
configureConsumer(answer);
83+
return answer;
84+
} else {
85+
throw new IllegalArgumentException("The type '" + getType() + "' is not valid!");
86+
}
87+
}
7088
}
7189
}

0 commit comments

Comments
 (0)