Implement SNMP v3 security support, remove traps support

This commit is contained in:
Viacheslav Klimov 2021-04-06 17:05:34 +03:00
parent 0045f00613
commit e52ac96c62
18 changed files with 1057 additions and 286 deletions

View File

@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.transport.snmp.AuthenticationProtocol;
import org.thingsboard.server.common.data.transport.snmp.PrivacyProtocol;
import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
@Data
@ -26,9 +28,23 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur
private String address;
private int port;
private SnmpProtocolVersion protocolVersion;
/*
* For SNMP v1 and v2c
* */
private String community;
/*
* For SNMP v3 with User Based Security Model
* */
private String username;
private String securityName;
private String authenticationPassphrase; // for SNMP v3
private String privacyPassphrase; // for SNMP v3
private String contextName;
private AuthenticationProtocol authenticationProtocol;
private String authenticationPassphrase;
private PrivacyProtocol privacyProtocol;
private String privacyPassphrase;
private String engineId;
@Override
public DeviceTransportType getType() {
@ -44,7 +60,6 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur
@JsonIgnore
private boolean isValid() {
return StringUtils.isNotBlank(address) && port > 0 &&
StringUtils.isNotBlank(securityName) && protocolVersion != null;
return true;
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.snmp;
import java.util.Arrays;
import java.util.Optional;
public enum AuthenticationProtocol {
SHA_1("1.3.6.1.6.3.10.1.1.3"),
SHA_224("1.3.6.1.6.3.10.1.1.4"),
SHA_256("1.3.6.1.6.3.10.1.1.5"),
SHA_384("1.3.6.1.6.3.10.1.1.6"),
SHA_512("1.3.6.1.6.3.10.1.1.7"),
MD5("1.3.6.1.6.3.10.1.1.2");
// oids taken from org.snmp4j.security.SecurityProtocol implementations
private final String oid;
AuthenticationProtocol(String oid) {
this.oid = oid;
}
public String getOid() {
return oid;
}
public static Optional<AuthenticationProtocol> forName(String name) {
return Arrays.stream(values())
.filter(protocol -> protocol.name().equalsIgnoreCase(name))
.findFirst();
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.snmp;
import java.util.Arrays;
import java.util.Optional;
public enum PrivacyProtocol {
DES("1.3.6.1.6.3.10.1.2.2"),
AES_128("1.3.6.1.6.3.10.1.2.4"),
AES_192("1.3.6.1.4.1.4976.2.2.1.1.1"),
AES_256("1.3.6.1.4.1.4976.2.2.1.1.2");
// oids taken from org.snmp4j.security.SecurityProtocol implementations
private final String oid;
PrivacyProtocol(String oid) {
this.oid = oid;
}
public String getOid() {
return oid;
}
public static Optional<PrivacyProtocol> forName(String name) {
return Arrays.stream(values())
.filter(protocol -> protocol.name().equalsIgnoreCase(name))
.findFirst();
}
}

View File

@ -19,10 +19,7 @@ public enum SnmpCommunicationSpec {
TELEMETRY_QUERYING(true),
CLIENT_ATTRIBUTES_QUERYING(true),
SHARED_ATTRIBUTES_SETTING,
TELEMETRY_TRAPS_RECEIVING,
CLIENT_ATTRIBUTES_TRAPS_RECEIVING;
SHARED_ATTRIBUTES_SETTING;
private final boolean isRepeatingQuerying;

View File

@ -1,25 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.snmp.configs;
import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
public class ClientAttributesTrapsReceivingSnmpCommunicationConfig extends SnmpCommunicationConfig {
@Override
public SnmpCommunicationSpec getSpec() {
return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_TRAPS_RECEIVING;
}
}

View File

@ -31,9 +31,7 @@ import java.util.List;
@JsonSubTypes({
@Type(value = TelemetryQueryingSnmpCommunicationConfig.class, name = "TELEMETRY_QUERYING"),
@Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"),
@Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING"),
@Type(value = TelemetryTrapsReceivingSnmpCommunicationConfig.class, name = "TELEMETRY_TRAPS_RECEIVING"),
@Type(value = ClientAttributesTrapsReceivingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_TRAPS_RECEIVING")
@Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING")
})
public abstract class SnmpCommunicationConfig {
protected List<SnmpMapping> mappings;

View File

@ -1,30 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.snmp.configs;
import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
public class TelemetryTrapsReceivingSnmpCommunicationConfig extends SnmpCommunicationConfig {
@Override
public SnmpCommunicationSpec getSpec() {
return SnmpCommunicationSpec.TELEMETRY_TRAPS_RECEIVING;
}
@Override
public boolean isValid() {
return false;
}
}

View File

@ -0,0 +1,118 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.snmp;
import lombok.RequiredArgsConstructor;
import org.snmp4j.AbstractTarget;
import org.snmp4j.CommunityTarget;
import org.snmp4j.Target;
import org.snmp4j.UserTarget;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModel;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
import org.thingsboard.server.transport.snmp.service.SnmpTransportService;
import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
@Service
@TbSnmpTransportComponent
@RequiredArgsConstructor
public class SnmpAuthService {
private final SnmpTransportService snmpTransportService;
@Value("${transport.snmp.underlying_protocol}")
private String snmpUnderlyingProtocol;
public Target setUpSnmpTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) {
AbstractTarget target;
SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion();
switch (protocolVersion) {
case V1:
CommunityTarget communityTargetV1 = new CommunityTarget();
communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1);
communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getCommunity()));
target = communityTargetV1;
break;
case V2C:
CommunityTarget communityTargetV2 = new CommunityTarget();
communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getCommunity()));
target = communityTargetV2;
break;
case V3:
OctetString username = new OctetString(deviceTransportConfig.getUsername());
OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName());
OctetString engineId = new OctetString(deviceTransportConfig.getEngineId());
OID authenticationProtocol = new OID(deviceTransportConfig.getAuthenticationProtocol().getOid());
OID privacyProtocol = new OID(deviceTransportConfig.getPrivacyProtocol().getOid());
OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase());
authenticationPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(authenticationProtocol, authenticationPassphrase, engineId.getValue()));
OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase());
privacyPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(privacyProtocol, authenticationProtocol, privacyPassphrase, engineId.getValue()));
USM usm = snmpTransportService.getSnmp().getUSM();
if (usm.hasUser(engineId, securityName)) {
usm.removeAllUsers(username, engineId);
}
usm.addLocalizedUser(
engineId.getValue(), username,
authenticationProtocol, authenticationPassphrase.getValue(),
privacyProtocol, privacyPassphrase.getValue()
);
UserTarget userTarget = new UserTarget();
userTarget.setSecurityName(securityName);
userTarget.setAuthoritativeEngineID(engineId.getValue());
userTarget.setSecurityModel(SecurityModel.SECURITY_MODEL_USM);
userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target = userTarget;
break;
default:
throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported");
}
target.setAddress(GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getAddress() + "/" + deviceTransportConfig.getPort()));
target.setTimeout(profileTransportConfig.getTimeoutMs());
target.setRetries(profileTransportConfig.getRetries());
target.setVersion(protocolVersion.getCode());
return target;
}
public void cleanUpSnmpAuthInfo(DeviceSessionContext sessionContext) {
SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration();
if (deviceTransportConfiguration.getProtocolVersion() == SnmpProtocolVersion.V3) {
OctetString username = new OctetString(deviceTransportConfiguration.getUsername());
OctetString engineId = new OctetString(deviceTransportConfiguration.getEngineId());
snmpTransportService.getSnmp().getUSM().removeAllUsers(username, engineId);
}
}
}

View File

@ -15,9 +15,9 @@
*/
package org.thingsboard.server.transport.snmp;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
@ -61,18 +61,18 @@ import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
public class SnmpTransportContext extends TransportContext {
@Getter
private final SnmpTransportService snmpTransportService;
private final TransportDeviceProfileCache deviceProfileCache;
private final TransportService transportService;
private final ProtoTransportEntityService protoEntityService;
private final SnmpTransportBalancingService balancingService;
@Getter
private final SnmpAuthService snmpAuthService;
private final Map<DeviceId, DeviceSessionContext> sessions = new ConcurrentHashMap<>();
private Collection<DeviceId> allSnmpDevicesIds = new ConcurrentLinkedDeque<>();
@Value("${transport.snmp.underlying_protocol}")
private String snmpUnderlyingProtocol;
@AfterStartUp(order = 2)
public void initDevicesSessions() {
log.info("Initializing SNMP devices sessions");
@ -116,8 +116,7 @@ public class SnmpTransportContext extends TransportContext {
DeviceSessionContext deviceSessionContext = new DeviceSessionContext(
device, deviceProfile, credentials.getCredentialsId(),
profileTransportConfiguration, deviceTransportConfiguration,
this, snmpTransportService, snmpUnderlyingProtocol
profileTransportConfiguration, deviceTransportConfiguration, this
);
registerSessionMsgListener(deviceSessionContext);
sessions.put(device.getId(), deviceSessionContext);
@ -155,6 +154,7 @@ public class SnmpTransportContext extends TransportContext {
if (sessionContext == null) return;
log.info("Destroying SNMP device session for device {}", sessionContext.getDevice().getId());
sessionContext.close();
snmpAuthService.cleanUpSnmpAuthInfo(sessionContext);
transportService.deregisterSession(sessionContext.getSessionInfo());
sessions.remove(sessionContext.getDeviceId());
snmpTransportService.cancelQueryingTasks(sessionContext);

View File

@ -19,29 +19,31 @@ import com.google.gson.JsonObject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.TbTransportService;
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
import org.thingsboard.server.common.data.transport.snmp.configs.RepeatingQueryingSnmpCommunicationConfig;
import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig;
import org.thingsboard.server.common.transport.TransportService;
@ -49,12 +51,12 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
import org.thingsboard.server.transport.snmp.SnmpTransportContext;
import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
@ -67,13 +69,11 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@TbSnmpTransportComponent
@Service
@Slf4j
public class SnmpTransportService implements TbTransportService, CommandResponder {
private final SnmpTransportContext snmpTransportContext;
public class SnmpTransportService implements TbTransportService {
private final TransportService transportService;
@Getter
@ -88,9 +88,7 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
@Value("${transport.snmp.underlying_protocol}")
private String snmpUnderlyingProtocol;
public SnmpTransportService(@Lazy SnmpTransportContext snmpTransportContext,
TransportService transportService) {
this.snmpTransportContext = snmpTransportContext;
public SnmpTransportService(TransportService transportService) {
this.transportService = transportService;
}
@ -102,7 +100,6 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel);
initializeSnmp();
initializeTrapsListener();
configureResponseProcessors();
log.info("SNMP transport service initialized");
@ -122,29 +119,9 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
}
snmp = new Snmp(transportMapping);
snmp.listen();
}
private void initializeTrapsListener() throws IOException {
int trapsListeningPort = 1062;
String bindingAddress = "0.0.0.0/" + trapsListeningPort;
TransportMapping<?> transportMapping;
switch (snmpUnderlyingProtocol) {
case "udp":
transportMapping = new DefaultUdpTransportMapping(new UdpAddress(bindingAddress));
break;
case "tcp":
transportMapping = new DefaultTcpTransportMapping(new TcpAddress(bindingAddress));
break;
default:
throw new IllegalArgumentException("Underlying protocol " + snmpUnderlyingProtocol + " for SNMP is not supported");
}
Snmp trapsSnmp = new Snmp(transportMapping);
trapsSnmp.addCommandResponder(this);
transportMapping.listen();
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
}
public void createQueryingTasks(DeviceSessionContext sessionContext) {
@ -177,12 +154,11 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
}
public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) throws IOException {
PDU request = createPdu(communicationConfig);
executeRequest(sessionContext, request);
sendRequest(sessionContext, communicationConfig, Collections.emptyMap());
}
public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) throws IOException {
PDU request = createPduWithValues(communicationConfig, values);
PDU request = createPdu(sessionContext, communicationConfig, values);
executeRequest(sessionContext, request);
}
@ -193,45 +169,36 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
}
}
private PDU createPdu(SnmpCommunicationConfig communicationConfig) {
PDU pdu = new PDU();
private PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) {
PDU pdu;
SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration();
SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion();
switch (snmpVersion) {
case V1:
case V2C:
pdu = new PDU();
break;
case V3:
ScopedPDU scopedPdu = new ScopedPDU();
scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName()));
scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId()));
pdu = scopedPdu;
break;
default:
throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported");
}
pdu.setType(communicationConfig.getMethod().getCode());
pdu.addAll(communicationConfig.getMappings().stream()
.map(mapping -> new VariableBinding(new OID(mapping.getOid())))
.filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey()))
.map(mapping -> Optional.ofNullable(values.get(mapping.getKey()))
.map(value -> new VariableBinding(new OID(mapping.getOid()), new OctetString(values.get(mapping.getKey()))))
.orElseGet(() -> new VariableBinding(new OID(mapping.getOid()))))
.collect(Collectors.toList()));
return pdu;
}
private PDU createPduWithValues(SnmpCommunicationConfig communicationConfig, Map<String, String> values) {
PDU pdu = new PDU();
pdu.setType(communicationConfig.getMethod().getCode());
pdu.addAll(communicationConfig.getMappings().stream()
.filter(mapping -> values.containsKey(mapping.getKey()))
.map(mapping -> {
String value = values.get(mapping.getKey());
return new VariableBinding(new OID(mapping.getOid()), new OctetString(value));
})
.collect(Collectors.toList()));
return pdu;
}
private void processTrap(CommandResponderEvent event) {
if (event.getPDU().getType() != PDU.TRAP) return;
snmpTransportContext.getSessions().stream()
.filter(sessionContext -> {
// TODO: SNMP v3 support
return sessionContext.getTarget().getSecurityName().equals(OctetString.fromByteArray(event.getSecurityName())) &&
sessionContext.getTarget().getAddress().equals(event.getPeerAddress());
})
.findFirst()
.ifPresentOrElse(sessionContext -> {
responseProcessingExecutor.execute(() -> processResponse(sessionContext, event.getPDU()));
}, () -> {
log.debug("SNMP event is from unknown source: {}", event);
});
}
public void processResponseEvent(DeviceSessionContext sessionContext, ResponseEvent event) {
((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext);
@ -243,7 +210,7 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
PDU response = event.getResponse();
if (response == null) {
log.warn("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID());
log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID());
return;
}
DeviceProfileId deviceProfileId = (DeviceProfileId) event.getUserObject();
@ -308,23 +275,17 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
}
private void configureResponseProcessors() {
Stream.of(SnmpCommunicationSpec.TELEMETRY_QUERYING, SnmpCommunicationSpec.TELEMETRY_TRAPS_RECEIVING)
.forEach(telemetrySpec -> {
responseProcessors.put(telemetrySpec, (response, sessionContext) -> {
TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(response);
transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, TransportServiceCallback.EMPTY);
log.debug("Posted telemetry for device {}: {}", sessionContext.getDeviceId(), response);
});
});
responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (response, sessionContext) -> {
TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(response);
transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, TransportServiceCallback.EMPTY);
log.debug("Posted telemetry for device {}: {}", sessionContext.getDeviceId(), response);
});
Stream.of(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, SnmpCommunicationSpec.CLIENT_ATTRIBUTES_TRAPS_RECEIVING)
.forEach(clientAttributesSpec -> {
responseProcessors.put(clientAttributesSpec, (response, sessionContext) -> {
TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(response);
transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, TransportServiceCallback.EMPTY);
log.debug("Posted attributes for device {}: {}", sessionContext.getDeviceId(), response);
});
});
responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (response, sessionContext) -> {
TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(response);
transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, TransportServiceCallback.EMPTY);
log.debug("Posted attributes for device {}: {}", sessionContext.getDeviceId(), response);
});
}
private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) {
@ -353,11 +314,6 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
}
}
@Override
public void processPdu(CommandResponderEvent event) {
processTrap(event);
}
@Override
public String getName() {
return "SNMP";

View File

@ -18,29 +18,15 @@ package org.thingsboard.server.transport.snmp.session;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.AbstractTarget;
import org.snmp4j.CommunityTarget;
import org.snmp4j.Target;
import org.snmp4j.UserTarget;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
import org.thingsboard.server.common.transport.SessionMsgListener;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
@ -50,6 +36,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse
import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
import org.thingsboard.server.transport.snmp.SnmpAuthService;
import org.thingsboard.server.transport.snmp.SnmpTransportContext;
import org.thingsboard.server.transport.snmp.service.SnmpTransportService;
@ -77,6 +64,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
private final SnmpTransportContext snmpTransportContext;
private final SnmpTransportService snmpTransportService;
private final SnmpAuthService snmpAuthService;
@Getter
@Setter
@ -84,7 +72,6 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
private final AtomicInteger msgIdSeq = new AtomicInteger(0);
@Getter
private boolean isActive = true;
private final String snmpUnderlyingProtocol;
@Getter
@Setter
@ -93,8 +80,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token,
SnmpDeviceProfileTransportConfiguration profileTransportConfiguration,
SnmpDeviceTransportConfiguration deviceTransportConfiguration,
SnmpTransportContext snmpTransportContext, SnmpTransportService snmpTransportService,
String snmpUnderlyingProtocol) {
SnmpTransportContext snmpTransportContext) {
super(UUID.randomUUID());
super.setDeviceId(device.getId());
super.setDeviceProfile(deviceProfile);
@ -102,12 +88,12 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
this.token = token;
this.snmpTransportContext = snmpTransportContext;
this.snmpTransportService = snmpTransportService;
this.snmpTransportService = snmpTransportContext.getSnmpTransportService();
this.snmpAuthService = snmpTransportContext.getSnmpAuthService();
this.profileTransportConfiguration = profileTransportConfiguration;
this.deviceTransportConfiguration = deviceTransportConfiguration;
this.snmpUnderlyingProtocol = snmpUnderlyingProtocol;
initializeTarget(profileTransportConfiguration, deviceTransportConfiguration);
}
@ -133,55 +119,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) {
log.trace("Initializing target for SNMP session of device {}", device);
AbstractTarget target;
SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion();
switch (protocolVersion) {
case V1:
CommunityTarget communityTargetV1 = new CommunityTarget();
communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1);
communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getSecurityName()));
target = communityTargetV1;
break;
case V2C:
CommunityTarget communityTargetV2 = new CommunityTarget();
communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getSecurityName()));
target = communityTargetV2;
break;
case V3:
USM usm = new USM();
SecurityModels.getInstance().addSecurityModel(usm);
OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName());
OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase());
OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase());
OID authenticationProtocol = AuthSHA.ID;
OID privacyProtocol = PrivDES.ID; // FIXME: to config
UsmUser user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase);
snmpTransportService.getSnmp().getUSM().addUser(user);
UserTarget userTarget = new UserTarget();
userTarget.setSecurityName(securityName);
userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target = userTarget;
break;
default:
throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported");
}
target.setAddress(GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getAddress() + "/" + deviceTransportConfig.getPort()));
target.setTimeout(profileTransportConfig.getTimeoutMs());
target.setRetries(profileTransportConfig.getRetries());
target.setVersion(protocolVersion.getCode());
this.target = target;
this.target = snmpAuthService.setUpSnmpTarget(profileTransportConfig, deviceTransportConfig);
log.info("SNMP target initialized: {}", target);
}

View File

@ -73,32 +73,6 @@ public class SnmpDeviceSimulatorV2 extends BaseAgent {
}
}
public static void main(String[] args) throws IOException {
SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public");
device.start();
device.setUpMappings(Map.of(
".1.3.6.1.2.1.1.1.50", "12",
".1.3.6.1.2.1.2.1.52", "56",
".1.3.6.1.2.1.3.1.54", "yes",
".1.3.6.1.2.1.7.1.58", ""
));
// while (true) {
// new Scanner(System.in).nextLine();
// device.sendTrap("127.0.0.1", 1062, Map.of(".1.3.6.1.2.87.1.56", "12"));
// System.out.println("sent");
// }
// Snmp snmp = new Snmp(device.transportMappings[0]);
// device.snmp.addCommandResponder(event -> {
// System.out.println(event);
// });
new Scanner(System.in).nextLine();
}
private final Target target;
private final Address address;

View File

@ -15,38 +15,731 @@
*/
package org.thingsboard.server.transport.snmp;
import org.snmp4j.UserTarget;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.TransportMapping;
import org.snmp4j.agent.BaseAgent;
import org.snmp4j.agent.CommandProcessor;
import org.snmp4j.agent.DuplicateRegistrationException;
import org.snmp4j.agent.MOGroup;
import org.snmp4j.agent.ManagedObject;
import org.snmp4j.agent.mo.DefaultMOMutableRow2PC;
import org.snmp4j.agent.mo.DefaultMOTable;
import org.snmp4j.agent.mo.MOAccessImpl;
import org.snmp4j.agent.mo.MOColumn;
import org.snmp4j.agent.mo.MOMutableColumn;
import org.snmp4j.agent.mo.MOMutableTableModel;
import org.snmp4j.agent.mo.MOScalar;
import org.snmp4j.agent.mo.MOTableIndex;
import org.snmp4j.agent.mo.MOTableRow;
import org.snmp4j.agent.mo.MOTableSubIndex;
import org.snmp4j.agent.mo.ext.AgentppSimulationMib;
import org.snmp4j.agent.mo.snmp.RowStatus;
import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
import org.snmp4j.agent.mo.snmp.StorageType;
import org.snmp4j.agent.mo.snmp.TransportDomains;
import org.snmp4j.agent.mo.snmp.VacmMIB;
import org.snmp4j.agent.mo.snmp4j.example.Snmp4jHeartbeatMib;
import org.snmp4j.agent.security.MutableVACM;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.security.AuthHMAC192SHA256;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivAES192;
import org.snmp4j.security.PrivAES256;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.Gauge32;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.SMIConstants;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.TimeTicks;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.Variable;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.TransportMappings;
import org.snmp4j.util.ThreadPool;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class SnmpDeviceSimulatorV3 extends SnmpDeviceSimulatorV2 {
public SnmpDeviceSimulatorV3(int port, String securityName, String authenticationPassphrase, String privacyPassphrase) throws IOException {
super(12, null);
// super(new File("conf.agent"), new File("bootCounter.agent"));
/**
* The TestAgent is a sample SNMP agent implementation of all
* features (MIB implementations) provided by the SNMP4J-Agent framework.
*
* Note, for snmp4s, this code is mostly a copy from snmp4j.
* And don't remove snmp users
*
*/
public class SnmpDeviceSimulatorV3 extends BaseAgent {
protected String address;
private Snmp4jHeartbeatMib heartbeatMIB;
private AgentppSimulationMib agentppSimulationMIB;
USM usm = new USM();
SecurityModels.getInstance().addSecurityModel(usm);
public SnmpDeviceSimulatorV3(CommandProcessor processor) throws IOException {
super(new File("SNMP4JTestAgentBC.cfg"), new File("SNMP4JTestAgentConfig.cfg"),
processor);
agent.setWorkerPool(ThreadPool.create("RequestPool", 4));
}
public void setUpMappings(Map<String, String> oidToResponseMappings) {
unregisterManagedObject(getSnmpv2MIB());
oidToResponseMappings.forEach((oid, response) -> {
registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response)));
});
}
protected void registerManagedObject(ManagedObject mo) {
try {
server.register(mo, null);
} catch (DuplicateRegistrationException ex) {
throw new RuntimeException(ex);
}
}
protected void unregisterManagedObject(MOGroup moGroup) {
moGroup.unregisterMOs(server, getContext(moGroup));
}
protected void registerManagedObjects() {
try {
server.register(createStaticIfTable(), null);
server.register(createStaticIfXTable(), null);
agentppSimulationMIB.registerMOs(server, null);
heartbeatMIB.registerMOs(server, null);
} catch (DuplicateRegistrationException ex) {
ex.printStackTrace();
}
}
protected void addNotificationTargets(SnmpTargetMIB targetMIB,
SnmpNotificationMIB notificationMIB) {
targetMIB.addDefaultTDomains();
targetMIB.addTargetAddress(new OctetString("notificationV2c"),
TransportDomains.transportDomainUdpIpv4,
new OctetString(new UdpAddress("127.0.0.1/162").getValue()),
200, 1,
new OctetString("notify"),
new OctetString("v2c"),
StorageType.permanent);
targetMIB.addTargetAddress(new OctetString("notificationV3"),
TransportDomains.transportDomainUdpIpv4,
new OctetString(new UdpAddress("127.0.0.1/1162").getValue()),
200, 1,
new OctetString("notify"),
new OctetString("v3notify"),
StorageType.permanent);
targetMIB.addTargetParams(new OctetString("v2c"),
MessageProcessingModel.MPv2c,
SecurityModel.SECURITY_MODEL_SNMPv2c,
new OctetString("cpublic"),
SecurityLevel.AUTH_PRIV,
StorageType.permanent);
targetMIB.addTargetParams(new OctetString("v3notify"),
MessageProcessingModel.MPv3,
SecurityModel.SECURITY_MODEL_USM,
new OctetString("v3notify"),
SecurityLevel.NOAUTH_NOPRIV,
StorageType.permanent);
notificationMIB.addNotifyEntry(new OctetString("default"),
new OctetString("notify"),
SnmpNotificationMIB.SnmpNotifyTypeEnum.inform,
StorageType.permanent);
}
protected void addViews(VacmMIB vacm) {
vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1,
new OctetString("cpublic"),
new OctetString("v1v2group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c,
new OctetString("cpublic"),
new OctetString("v1v2group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHADES"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("MD5DES"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("TEST"),
new OctetString("v3test"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHA"),
new OctetString("v3restricted"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHAAES128"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHAAES192"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("SHAAES256"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("MD5AES128"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("MD5AES192"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("MD5AES256"),
new OctetString("v3group"),
StorageType.nonVolatile);
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("aboba"),
new OctetString("v3group"),
StorageType.nonVolatile);
//============================================//
// agent5-auth-priv
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("agent5"),
new OctetString("v3group"),
StorageType.nonVolatile);
//===========================================//
// agent002
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("agent002"),
new OctetString("v3group"),
StorageType.nonVolatile);
//===========================================//
// user001-auth-no-priv
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("user001"),
new OctetString("group001"),
StorageType.nonVolatile);
//===========================================//
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("v3notify"),
new OctetString("v3group"),
StorageType.nonVolatile);
//===========================================//
// group auth no priv
vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
new OctetString("v3notify-auth"),
new OctetString("group001"),
StorageType.nonVolatile);
//===========================================//
// my conf
vacm.addAccess(new OctetString("group001"), new OctetString("public"),
SecurityModel.SECURITY_MODEL_USM,
SecurityLevel.AUTH_NOPRIV,
MutableVACM.VACM_MATCH_EXACT,
new OctetString("fullReadView"),
new OctetString("fullWriteView"),
new OctetString("fullNotifyView"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"),
SecurityModel.SECURITY_MODEL_ANY,
SecurityLevel.NOAUTH_NOPRIV,
MutableVACM.VACM_MATCH_EXACT,
new OctetString("fullReadView"),
new OctetString("fullWriteView"),
new OctetString("fullNotifyView"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v3group"), new OctetString(),
SecurityModel.SECURITY_MODEL_USM,
SecurityLevel.AUTH_PRIV,
MutableVACM.VACM_MATCH_EXACT,
new OctetString("fullReadView"),
new OctetString("fullWriteView"),
new OctetString("fullNotifyView"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v3restricted"), new OctetString(),
SecurityModel.SECURITY_MODEL_USM,
SecurityLevel.NOAUTH_NOPRIV,
MutableVACM.VACM_MATCH_EXACT,
new OctetString("restrictedReadView"),
new OctetString("restrictedWriteView"),
new OctetString("restrictedNotifyView"),
StorageType.nonVolatile);
vacm.addAccess(new OctetString("v3test"), new OctetString(),
SecurityModel.SECURITY_MODEL_USM,
SecurityLevel.AUTH_PRIV,
MutableVACM.VACM_MATCH_EXACT,
new OctetString("testReadView"),
new OctetString("testWriteView"),
new OctetString("testNotifyView"),
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("fullNotifyView"), new OID("1.3"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("restrictedReadView"),
new OID("1.3.6.1.2"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("restrictedWriteView"),
new OID("1.3.6.1.2.1"),
new OctetString(),
VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
new OID("1.3.6.1.2"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
new OID("1.3.6.1.6.3.1"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("testReadView"),
new OID("1.3.6.1.2"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("testReadView"),
new OID("1.3.6.1.2.1.1"),
new OctetString(), VacmMIB.vacmViewExcluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("testWriteView"),
new OID("1.3.6.1.2.1"),
new OctetString(),
VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
vacm.addViewTreeFamily(new OctetString("testNotifyView"),
new OID("1.3.6.1.2"),
new OctetString(), VacmMIB.vacmViewIncluded,
StorageType.nonVolatile);
}
protected void addUsmUser(USM usm) {
UsmUser user = new UsmUser(new OctetString("SHADES"),
AuthSHA.ID,
new OctetString("SHADESAuthPassword"),
PrivDES.ID,
new OctetString("SHADESPrivPassword"));
// usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
usm.addUser(user.getSecurityName(), null, user);
user = new UsmUser(new OctetString("TEST"),
AuthSHA.ID,
new OctetString("maplesyrup"),
PrivDES.ID,
new OctetString("maplesyrup"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("SHA"),
AuthSHA.ID,
new OctetString("SHAAuthPassword"),
null,
null);
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("SHADES"),
AuthSHA.ID,
new OctetString("SHADESAuthPassword"),
PrivDES.ID,
new OctetString("SHADESPrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("MD5DES"),
AuthMD5.ID,
new OctetString("MD5DESAuthPassword"),
PrivDES.ID,
new OctetString("MD5DESPrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("SHAAES128"),
AuthSHA.ID,
new OctetString("SHAAES128AuthPassword"),
PrivAES128.ID,
new OctetString("SHAAES128PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("SHAAES192"),
AuthSHA.ID,
new OctetString("SHAAES192AuthPassword"),
PrivAES192.ID,
new OctetString("SHAAES192PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("SHAAES256"),
AuthSHA.ID,
new OctetString("SHAAES256AuthPassword"),
PrivAES256.ID,
new OctetString("SHAAES256PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("MD5AES128"),
AuthMD5.ID,
new OctetString("MD5AES128AuthPassword"),
PrivAES128.ID,
new OctetString("MD5AES128PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("MD5AES192"),
AuthHMAC192SHA256.ID,
new OctetString("MD5AES192AuthPassword"),
PrivAES192.ID,
new OctetString("MD5AES192PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
//==============================================================
user = new UsmUser(new OctetString("MD5AES256"),
AuthMD5.ID,
new OctetString("MD5AES256AuthPassword"),
PrivAES256.ID,
new OctetString("MD5AES256PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
user = new UsmUser(new OctetString("MD5AES256"),
AuthMD5.ID,
new OctetString("MD5AES256AuthPassword"),
PrivAES256.ID,
new OctetString("MD5AES256PrivPassword"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
OctetString securityName = new OctetString("aboba");
OctetString authenticationPassphrase = new OctetString("abobaaboba");
OctetString privacyPassphrase = new OctetString("abobaaboba");
OID authenticationProtocol = AuthSHA.ID;
OID privacyProtocol = PrivDES.ID;
OID privacyProtocol = PrivDES.ID; // FIXME: to config
user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase);
usm.addUser(user);
UsmUser user = new UsmUser(new OctetString(securityName), authenticationProtocol, new OctetString(authenticationPassphrase), privacyProtocol, new OctetString(privacyPassphrase));
//===============================================================//
user = new UsmUser(new OctetString("agent5"),
AuthSHA.ID,
new OctetString("authpass"),
PrivDES.ID,
new OctetString("privpass"));
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
//===============================================================//
// user001
user = new UsmUser(new OctetString("user001"),
AuthSHA.ID,
new OctetString("authpass"),
null, null);
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
//===============================================================//
// user002
user = new UsmUser(new OctetString("user001"),
null,
null,
null, null);
usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
//===============================================================//
user = new UsmUser(new OctetString("v3notify"),
null,
null,
null,
null);
usm.addUser(user.getSecurityName(), null, user);
this.usm = usm;
}
public void initV3(UsmUser user, String securityName) {
// snmp.getUSM().addUser(user);
private static DefaultMOTable createStaticIfXTable() {
MOTableSubIndex[] subIndexes =
new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
MOColumn[] columns = new MOColumn[19];
int c = 0;
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
MOAccessImpl.ACCESS_READ_ONLY); // ifName
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifInMulticastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifInBroadcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifOutMulticastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifOutBroadcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCInOctets
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCInUcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCInMulticastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCInBroadcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutOctets
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutUcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutMulticastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutBroadcastPkts
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_WRITE); // ifLinkUpDownTrapEnable
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
MOAccessImpl.ACCESS_READ_ONLY); // ifHighSpeed
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_WRITE); // ifPromiscuousMode
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_ONLY); // ifConnectorPresent
columns[c++] =
new MOMutableColumn(c, SMIConstants.SYNTAX_OCTET_STRING, // ifAlias
MOAccessImpl.ACCESS_READ_WRITE, null);
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_TIMETICKS,
MOAccessImpl.ACCESS_READ_ONLY); // ifCounterDiscontinuityTime
UserTarget userTarget = new UserTarget();
userTarget.setSecurityName(new OctetString(securityName));
userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
DefaultMOTable ifXTable =
new DefaultMOTable(new OID("1.3.6.1.2.1.31.1.1.1"), indexDef, columns);
MOMutableTableModel model = (MOMutableTableModel) ifXTable.getModel();
Variable[] rowValues1 = new Variable[] {
new OctetString("Ethernet-0"),
new Integer32(1),
new Integer32(2),
new Integer32(3),
new Integer32(4),
new Integer32(5),
new Integer32(6),
new Integer32(7),
new Integer32(8),
new Integer32(9),
new Integer32(10),
new Integer32(11),
new Integer32(12),
new Integer32(13),
new Integer32(14),
new Integer32(15),
new Integer32(16),
new OctetString("My eth"),
new TimeTicks(1000)
};
Variable[] rowValues2 = new Variable[] {
new OctetString("Loopback"),
new Integer32(21),
new Integer32(22),
new Integer32(23),
new Integer32(24),
new Integer32(25),
new Integer32(26),
new Integer32(27),
new Integer32(28),
new Integer32(29),
new Integer32(30),
new Integer32(31),
new Integer32(32),
new Integer32(33),
new Integer32(34),
new Integer32(35),
new Integer32(36),
new OctetString("My loop"),
new TimeTicks(2000)
};
model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
ifXTable.setVolatile(true);
return ifXTable;
}
}
private static DefaultMOTable createStaticIfTable() {
MOTableSubIndex[] subIndexes =
new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
MOColumn[] columns = new MOColumn[8];
int c = 0;
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_ONLY); // ifIndex
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
MOAccessImpl.ACCESS_READ_ONLY); // ifDescr
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_ONLY); // ifType
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
MOAccessImpl.ACCESS_READ_ONLY); // ifPhysAddress
columns[c++] =
new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, // ifAdminStatus
MOAccessImpl.ACCESS_READ_WRITE, null);
columns[c++] =
new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
MOAccessImpl.ACCESS_READ_ONLY); // ifOperStatus
DefaultMOTable ifTable =
new DefaultMOTable(new OID("1.3.6.1.2.1.2.2.1"), indexDef, columns);
MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
Variable[] rowValues1 = new Variable[] {
new Integer32(1),
new OctetString("eth0"),
new Integer32(6),
new Integer32(1500),
new Gauge32(100000000),
new OctetString("00:00:00:00:01"),
new Integer32(1),
new Integer32(1)
};
Variable[] rowValues2 = new Variable[] {
new Integer32(2),
new OctetString("loopback"),
new Integer32(24),
new Integer32(1500),
new Gauge32(10000000),
new OctetString("00:00:00:00:02"),
new Integer32(1),
new Integer32(1)
};
model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
ifTable.setVolatile(true);
return ifTable;
}
private static DefaultMOTable createStaticSnmp4sTable() {
MOTableSubIndex[] subIndexes =
new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
MOColumn[] columns = new MOColumn[8];
int c = 0;
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_NULL, MOAccessImpl.ACCESS_READ_ONLY); // testNull
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // testBoolean
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifType
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, MOAccessImpl.ACCESS_READ_ONLY); //ifPhysAddress
columns[c++] = new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_WRITE,
null);
// ifAdminStatus
columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY);
// ifOperStatus
DefaultMOTable ifTable =
new DefaultMOTable(new OID("1.3.6.1.4.1.50000.1.1"), indexDef, columns);
MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
Variable[] rowValues1 = new Variable[] {
new Integer32(1),
new OctetString("eth0"),
new Integer32(6),
new Integer32(1500),
new Gauge32(100000000),
new OctetString("00:00:00:00:01"),
new Integer32(1),
new Integer32(1)
};
Variable[] rowValues2 = new Variable[] {
new Integer32(2),
new OctetString("loopback"),
new Integer32(24),
new Integer32(1500),
new Gauge32(10000000),
new OctetString("00:00:00:00:02"),
new Integer32(1),
new Integer32(1)
};
model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
ifTable.setVolatile(true);
return ifTable;
}
protected void initTransportMappings() throws IOException {
transportMappings = new TransportMapping[2];
Address addr = GenericAddress.parse(address);
TransportMapping tm =
TransportMappings.getInstance().createTransportMapping(addr);
transportMappings[0] = tm;
transportMappings[1] = new DefaultTcpTransportMapping(new TcpAddress(address));
}
public void start(String ip, String port) throws IOException {
address = ip + "/" + port;
//BasicConfigurator.configure();
init();
addShutdownHook();
// loadConfig(ImportModes.REPLACE_CREATE);
getServer().addContext(new OctetString("public"));
finishInit();
run();
sendColdStartNotification();
}
protected void unregisterManagedObjects() {
// here we should unregister those objects previously registered...
}
protected void addCommunities(SnmpCommunityMIB communityMIB) {
Variable[] com2sec = new Variable[] {
new OctetString("public"), // community name
new OctetString("cpublic"), // security name
getAgent().getContextEngineID(), // local engine ID
new OctetString("public"), // default context name
new OctetString(), // transport tag
new Integer32(StorageType.nonVolatile), // storage type
new Integer32(RowStatus.active) // row status
};
MOTableRow row =
communityMIB.getSnmpCommunityEntry().createRow(
new OctetString("public2public").toSubIndex(true), com2sec);
communityMIB.getSnmpCommunityEntry().addRow((SnmpCommunityMIB.SnmpCommunityEntryRow) row);
// snmpCommunityMIB.setSourceAddressFiltering(true);
}
protected void registerSnmpMIBs() {
heartbeatMIB = new Snmp4jHeartbeatMib(super.getNotificationOriginator(),
new OctetString(),
super.snmpv2MIB.getSysUpTime());
agentppSimulationMIB = new AgentppSimulationMib();
super.registerSnmpMIBs();
}
protected void initMessageDispatcher() {
this.dispatcher = new MessageDispatcherImpl();
this.mpv3 = new MPv3(this.agent.getContextEngineID().getValue());
this.usm = new USM(SecurityProtocols.getInstance(), this.agent.getContextEngineID(), this.updateEngineBoots());
SecurityModels.getInstance().addSecurityModel(this.usm);
SecurityProtocols.getInstance().addDefaultProtocols();
this.dispatcher.addMessageProcessingModel(new MPv1());
this.dispatcher.addMessageProcessingModel(new MPv2c());
this.dispatcher.addMessageProcessingModel(this.mpv3);
this.initSnmpSession();
}
}

View File

@ -19,7 +19,7 @@ import java.io.IOException;
import java.util.Map;
import java.util.Scanner;
public class SnmpTest {
public class SnmpTestV2 {
public static void main(String[] args) throws IOException {
SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public");

View File

@ -0,0 +1,46 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.snmp;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.agent.CommandProcessor;
import org.snmp4j.mp.MPv3;
import org.snmp4j.smi.OctetString;
import java.io.IOException;
import java.util.Map;
import java.util.Scanner;
public class SnmpTestV3 {
public static void main(String[] args) throws IOException {
SnmpDeviceSimulatorV3 device = new SnmpDeviceSimulatorV3(new CommandProcessor(new OctetString(MPv3.createLocalEngineID())) {
@Override
public void processPdu(CommandResponderEvent event) {
System.out.println("event: " + event);
}
});
device.start("0.0.0.0", "1610");
device.setUpMappings(Map.of(
".1.3.6.1.2.1.1.1.50", "12",
".1.3.6.1.2.1.2.1.52", "56",
".1.3.6.1.2.1.3.1.54", "yes",
".1.3.6.1.2.1.7.1.58", ""
));
new Scanner(System.in).nextLine();
}
}

View File

@ -38,16 +38,6 @@
"dataType": "STRING"
}
]
},
{
"spec": "TELEMETRY_TRAPS_RECEIVING",
"mappings": [
{
"oid": ".1.3.6.1.2.8.7.1.56",
"key": "temperature_trap",
"dataType": "LONG"
}
]
}
]
}

View File

@ -0,0 +1,13 @@
{
"address": "192.168.3.23",
"port": 1610,
"protocolVersion": "V3",
"username": "tb-user",
"engineId": "qwertyuioa",
"securityName": "tb-user",
"authenticationProtocol": "SHA_512",
"authenticationPassphrase": "sdfghjkloifgh",
"privacyProtocol": "DES",
"privacyPassphrase": "rtytguijokod"
}

View File

@ -1,6 +1,6 @@
{
"address": "127.0.0.1",
"port": 1610,
"password": "public",
"community": "public",
"protocolVersion": "V2C"
}