Commit 4ce818074b34f955e0aba0b36fd7d9f61d2d4ca2

Authored by Andrew Shvayka
Committed by GitHub
2 parents 0045f006 a1e4bbbb

Merge pull request #4455 from ViacheslavKlimov/feature/snmp-improvement

Improvements for SNMP: SNMP v3 security, RPC, refactoring
Showing 25 changed files with 1439 additions and 456 deletions
... ... @@ -17,18 +17,39 @@ package org.thingsboard.server.common.data.device.data;
17 17
18 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 19 import lombok.Data;
  20 +import lombok.ToString;
  21 +import org.apache.commons.lang3.ObjectUtils;
20 22 import org.apache.commons.lang3.StringUtils;
21 23 import org.thingsboard.server.common.data.DeviceTransportType;
  24 +import org.thingsboard.server.common.data.transport.snmp.AuthenticationProtocol;
  25 +import org.thingsboard.server.common.data.transport.snmp.PrivacyProtocol;
22 26 import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
23 27
  28 +import java.util.Objects;
  29 +
24 30 @Data
  31 +@ToString(of = {"host", "port", "protocolVersion"})
25 32 public class SnmpDeviceTransportConfiguration implements DeviceTransportConfiguration {
26   - private String address;
27   - private int port;
  33 + private String host;
  34 + private Integer port;
28 35 private SnmpProtocolVersion protocolVersion;
  36 +
  37 + /*
  38 + * For SNMP v1 and v2c
  39 + * */
  40 + private String community;
  41 +
  42 + /*
  43 + * For SNMP v3
  44 + * */
  45 + private String username;
29 46 private String securityName;
30   - private String authenticationPassphrase; // for SNMP v3
31   - private String privacyPassphrase; // for SNMP v3
  47 + private String contextName;
  48 + private AuthenticationProtocol authenticationProtocol;
  49 + private String authenticationPassphrase;
  50 + private PrivacyProtocol privacyProtocol;
  51 + private String privacyPassphrase;
  52 + private String engineId;
32 53
33 54 @Override
34 55 public DeviceTransportType getType() {
... ... @@ -44,7 +65,21 @@ public class SnmpDeviceTransportConfiguration implements DeviceTransportConfigur
44 65
45 66 @JsonIgnore
46 67 private boolean isValid() {
47   - return StringUtils.isNotBlank(address) && port > 0 &&
48   - StringUtils.isNotBlank(securityName) && protocolVersion != null;
  68 + boolean isValid = StringUtils.isNotBlank(host) && port != null && protocolVersion != null;
  69 + if (isValid) {
  70 + switch (protocolVersion) {
  71 + case V1:
  72 + case V2C:
  73 + isValid = StringUtils.isNotEmpty(community);
  74 + break;
  75 + case V3:
  76 + isValid = StringUtils.isNotBlank(username) && StringUtils.isNotBlank(securityName)
  77 + && contextName != null && authenticationProtocol != null
  78 + && StringUtils.isNotBlank(authenticationPassphrase)
  79 + && privacyProtocol != null && privacyPassphrase != null && engineId != null;
  80 + break;
  81 + }
  82 + }
  83 + return isValid;
49 84 }
50 85 }
... ...
... ... @@ -18,14 +18,15 @@ package org.thingsboard.server.common.data.device.profile;
18 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 19 import lombok.Data;
20 20 import org.thingsboard.server.common.data.DeviceTransportType;
21   -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig;
  21 +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
  22 +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig;
22 23
23 24 import java.util.List;
24 25
25 26 @Data
26 27 public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
27   - private int timeoutMs;
28   - private int retries;
  28 + private Integer timeoutMs;
  29 + private Integer retries;
29 30 private List<SnmpCommunicationConfig> communicationConfigs;
30 31
31 32 @Override
... ... @@ -36,12 +37,16 @@ public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTra
36 37 @Override
37 38 public void validate() {
38 39 if (!isValid()) {
39   - throw new IllegalArgumentException("Transport configuration is not valid");
  40 + throw new IllegalArgumentException("SNMP transport configuration is not valid");
40 41 }
41 42 }
42 43
43 44 @JsonIgnore
44 45 private boolean isValid() {
45   - return true;
  46 + return timeoutMs != null && timeoutMs >= 0 && retries != null && retries >= 0
  47 + && communicationConfigs != null
  48 + && communicationConfigs.stream().allMatch(config -> config != null && config.isValid())
  49 + && communicationConfigs.stream().flatMap(config -> config.getAllMappings().stream()).map(SnmpMapping::getOid)
  50 + .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getAllMappings().size()).sum();
46 51 }
47 52 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.transport.snmp;
  17 +
  18 +import java.util.Arrays;
  19 +import java.util.Optional;
  20 +
  21 +public enum AuthenticationProtocol {
  22 + SHA_1("1.3.6.1.6.3.10.1.1.3"),
  23 + SHA_224("1.3.6.1.6.3.10.1.1.4"),
  24 + SHA_256("1.3.6.1.6.3.10.1.1.5"),
  25 + SHA_384("1.3.6.1.6.3.10.1.1.6"),
  26 + SHA_512("1.3.6.1.6.3.10.1.1.7"),
  27 + MD5("1.3.6.1.6.3.10.1.1.2");
  28 +
  29 + // oids taken from org.snmp4j.security.SecurityProtocol implementations
  30 + private final String oid;
  31 +
  32 + AuthenticationProtocol(String oid) {
  33 + this.oid = oid;
  34 + }
  35 +
  36 + public String getOid() {
  37 + return oid;
  38 + }
  39 +
  40 + public static Optional<AuthenticationProtocol> forName(String name) {
  41 + return Arrays.stream(values())
  42 + .filter(protocol -> protocol.name().equalsIgnoreCase(name))
  43 + .findFirst();
  44 + }
  45 +}
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/PrivacyProtocol.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesTrapsReceivingSnmpCommunicationConfig.java
... ... @@ -13,13 +13,31 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp;
17 17
18   -import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
  18 +import java.util.Arrays;
  19 +import java.util.Optional;
19 20
20   -public class ClientAttributesTrapsReceivingSnmpCommunicationConfig extends SnmpCommunicationConfig {
21   - @Override
22   - public SnmpCommunicationSpec getSpec() {
23   - return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_TRAPS_RECEIVING;
  21 +public enum PrivacyProtocol {
  22 + DES("1.3.6.1.6.3.10.1.2.2"),
  23 + AES_128("1.3.6.1.6.3.10.1.2.4"),
  24 + AES_192("1.3.6.1.4.1.4976.2.2.1.1.1"),
  25 + AES_256("1.3.6.1.4.1.4976.2.2.1.1.2");
  26 +
  27 + // oids taken from org.snmp4j.security.SecurityProtocol implementations
  28 + private final String oid;
  29 +
  30 + PrivacyProtocol(String oid) {
  31 + this.oid = oid;
  32 + }
  33 +
  34 + public String getOid() {
  35 + return oid;
  36 + }
  37 +
  38 + public static Optional<PrivacyProtocol> forName(String name) {
  39 + return Arrays.stream(values())
  40 + .filter(protocol -> protocol.name().equalsIgnoreCase(name))
  41 + .findFirst();
24 42 }
25 43 }
... ...
... ... @@ -16,25 +16,10 @@
16 16 package org.thingsboard.server.common.data.transport.snmp;
17 17
18 18 public enum SnmpCommunicationSpec {
19   - TELEMETRY_QUERYING(true),
20   - CLIENT_ATTRIBUTES_QUERYING(true),
  19 + TELEMETRY_QUERYING,
21 20
  21 + CLIENT_ATTRIBUTES_QUERYING,
22 22 SHARED_ATTRIBUTES_SETTING,
23 23
24   - TELEMETRY_TRAPS_RECEIVING,
25   - CLIENT_ATTRIBUTES_TRAPS_RECEIVING;
26   -
27   - private final boolean isRepeatingQuerying;
28   -
29   - SnmpCommunicationSpec() {
30   - this.isRepeatingQuerying = false;
31   - }
32   -
33   - SnmpCommunicationSpec(boolean isRepeatingQuerying) {
34   - this.isRepeatingQuerying = isRepeatingQuerying;
35   - }
36   -
37   - public boolean isRepeatingQuerying() {
38   - return isRepeatingQuerying;
39   - }
  24 + TO_DEVICE_RPC_REQUEST,
40 25 }
... ...
... ... @@ -16,13 +16,17 @@
16 16 package org.thingsboard.server.common.data.transport.snmp;
17 17
18 18 import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import lombok.AllArgsConstructor;
19 20 import lombok.Data;
  21 +import lombok.NoArgsConstructor;
20 22 import org.apache.commons.lang3.StringUtils;
21 23 import org.thingsboard.server.common.data.kv.DataType;
22 24
23 25 import java.util.regex.Pattern;
24 26
25 27 @Data
  28 +@AllArgsConstructor
  29 +@NoArgsConstructor
26 30 public class SnmpMapping {
27 31 private String oid;
28 32 private String key;
... ... @@ -32,7 +36,6 @@ public class SnmpMapping {
32 36
33 37 @JsonIgnore
34 38 public boolean isValid() {
35   - return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() &&
36   - StringUtils.isNotBlank(key) && dataType != null;
  39 + return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && StringUtils.isNotBlank(key);
37 40 }
38 41 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/MultipleMappingsSnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryTrapsReceivingSnmpCommunicationConfig.java
... ... @@ -13,18 +13,24 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config;
17 17
18   -import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
  20 +
  21 +import java.util.List;
  22 +
  23 +@Data
  24 +public abstract class MultipleMappingsSnmpCommunicationConfig implements SnmpCommunicationConfig {
  25 + protected List<SnmpMapping> mappings;
19 26
20   -public class TelemetryTrapsReceivingSnmpCommunicationConfig extends SnmpCommunicationConfig {
21 27 @Override
22   - public SnmpCommunicationSpec getSpec() {
23   - return SnmpCommunicationSpec.TELEMETRY_TRAPS_RECEIVING;
  28 + public boolean isValid() {
  29 + return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid());
24 30 }
25 31
26 32 @Override
27   - public boolean isValid() {
28   - return false;
  33 + public List<SnmpMapping> getAllMappings() {
  34 + return mappings;
29 35 }
30 36 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/RepeatingQueryingSnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/RepeatingQueryingSnmpCommunicationConfig.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config;
17 17
18 18 import lombok.Data;
19 19 import lombok.EqualsAndHashCode;
... ... @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.transport.snmp.SnmpMethod;
21 21
22 22 @EqualsAndHashCode(callSuper = true)
23 23 @Data
24   -public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommunicationConfig {
  24 +public abstract class RepeatingQueryingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig {
25 25 private Long queryingFrequencyMs;
26 26
27 27 @Override
... ... @@ -31,6 +31,6 @@ public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommu
31 31
32 32 @Override
33 33 public boolean isValid() {
34   - return true;
  34 + return queryingFrequencyMs != null && queryingFrequencyMs > 0 && super.isValid();
35 35 }
36 36 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/SnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SnmpCommunicationConfig.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config;
17 17
18 18 import com.fasterxml.jackson.annotation.JsonIgnore;
19 19 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
... ... @@ -23,6 +23,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
23 23 import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
24 24 import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
25 25 import org.thingsboard.server.common.data.transport.snmp.SnmpMethod;
  26 +import org.thingsboard.server.common.data.transport.snmp.config.impl.ClientAttributesQueryingSnmpCommunicationConfig;
  27 +import org.thingsboard.server.common.data.transport.snmp.config.impl.SharedAttributesSettingSnmpCommunicationConfig;
  28 +import org.thingsboard.server.common.data.transport.snmp.config.impl.TelemetryQueryingSnmpCommunicationConfig;
26 29
27 30 import java.util.List;
28 31
... ... @@ -31,32 +34,21 @@ import java.util.List;
31 34 @JsonSubTypes({
32 35 @Type(value = TelemetryQueryingSnmpCommunicationConfig.class, name = "TELEMETRY_QUERYING"),
33 36 @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"),
34   - @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING"),
35   - @Type(value = TelemetryTrapsReceivingSnmpCommunicationConfig.class, name = "TELEMETRY_TRAPS_RECEIVING"),
36   - @Type(value = ClientAttributesTrapsReceivingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_TRAPS_RECEIVING")
  37 + @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING")
37 38 })
38   -public abstract class SnmpCommunicationConfig {
39   - protected List<SnmpMapping> mappings;
  39 +public interface SnmpCommunicationConfig {
40 40
41   - public List<SnmpMapping> getMappings() {
42   - return mappings;
43   - }
44   -
45   - public abstract SnmpCommunicationSpec getSpec();
  41 + SnmpCommunicationSpec getSpec();
46 42
47 43 @JsonIgnore
48   - public SnmpMethod getMethod() {
  44 + default SnmpMethod getMethod() {
49 45 return null;
50 46 }
51 47
52 48 @JsonIgnore
53   - public boolean isValid() {
54   - return true;
55   - }
  49 + List<SnmpMapping> getAllMappings();
  50 +
  51 + @JsonIgnore
  52 + boolean isValid();
56 53
57   - public void validate() {
58   - if (!isValid()) {
59   - throw new IllegalArgumentException("Communication config is not valid");
60   - }
61   - }
62 54 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ClientAttributesQueryingSnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesQueryingSnmpCommunicationConfig.java
... ... @@ -13,13 +13,16 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config.impl;
17 17
18 18 import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
  19 +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig;
19 20
20 21 public class ClientAttributesQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig {
  22 +
21 23 @Override
22 24 public SnmpCommunicationSpec getSpec() {
23 25 return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING;
24 26 }
  27 +
25 28 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/SharedAttributesSettingSnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SharedAttributesSettingSnmpCommunicationConfig.java
... ... @@ -13,12 +13,14 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config.impl;
17 17
18 18 import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
19 19 import org.thingsboard.server.common.data.transport.snmp.SnmpMethod;
  20 +import org.thingsboard.server.common.data.transport.snmp.config.MultipleMappingsSnmpCommunicationConfig;
  21 +
  22 +public class SharedAttributesSettingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig {
20 23
21   -public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunicationConfig {
22 24 @Override
23 25 public SnmpCommunicationSpec getSpec() {
24 26 return SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING;
... ... @@ -29,8 +31,4 @@ public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunic
29 31 return SnmpMethod.SET;
30 32 }
31 33
32   - @Override
33   - public boolean isValid() {
34   - return true;
35   - }
36 34 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/TelemetryQueryingSnmpCommunicationConfig.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryQueryingSnmpCommunicationConfig.java
... ... @@ -13,17 +13,20 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.data.transport.snmp.configs;
  16 +package org.thingsboard.server.common.data.transport.snmp.config.impl;
17 17
18 18 import lombok.Data;
19 19 import lombok.EqualsAndHashCode;
20 20 import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
  21 +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig;
21 22
22 23 @EqualsAndHashCode(callSuper = true)
23 24 @Data
24 25 public class TelemetryQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig {
  26 +
25 27 @Override
26 28 public SnmpCommunicationSpec getSpec() {
27 29 return SnmpCommunicationSpec.TELEMETRY_QUERYING;
28 30 }
  31 +
29 32 }
... ...
... ... @@ -15,9 +15,9 @@
15 15 */
16 16 package org.thingsboard.server.transport.snmp;
17 17
  18 +import lombok.Getter;
18 19 import lombok.RequiredArgsConstructor;
19 20 import lombok.extern.slf4j.Slf4j;
20   -import org.springframework.beans.factory.annotation.Value;
21 21 import org.springframework.context.event.EventListener;
22 22 import org.springframework.stereotype.Component;
23 23 import org.thingsboard.server.common.data.Device;
... ... @@ -42,6 +42,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
42 42 import org.thingsboard.server.queue.util.AfterStartUp;
43 43 import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
44 44 import org.thingsboard.server.transport.snmp.service.ProtoTransportEntityService;
  45 +import org.thingsboard.server.transport.snmp.service.SnmpAuthService;
45 46 import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService;
46 47 import org.thingsboard.server.transport.snmp.service.SnmpTransportService;
47 48 import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
... ... @@ -61,18 +62,18 @@ import java.util.stream.Collectors;
61 62 @Slf4j
62 63 @RequiredArgsConstructor
63 64 public class SnmpTransportContext extends TransportContext {
  65 + @Getter
64 66 private final SnmpTransportService snmpTransportService;
65 67 private final TransportDeviceProfileCache deviceProfileCache;
66 68 private final TransportService transportService;
67 69 private final ProtoTransportEntityService protoEntityService;
68 70 private final SnmpTransportBalancingService balancingService;
  71 + @Getter
  72 + private final SnmpAuthService snmpAuthService;
69 73
70 74 private final Map<DeviceId, DeviceSessionContext> sessions = new ConcurrentHashMap<>();
71 75 private Collection<DeviceId> allSnmpDevicesIds = new ConcurrentLinkedDeque<>();
72 76
73   - @Value("${transport.snmp.underlying_protocol}")
74   - private String snmpUnderlyingProtocol;
75   -
76 77 @AfterStartUp(order = 2)
77 78 public void initDevicesSessions() {
78 79 log.info("Initializing SNMP devices sessions");
... ... @@ -89,18 +90,12 @@ public class SnmpTransportContext extends TransportContext {
89 90 managedDevicesIds.stream()
90 91 .map(protoEntityService::getDeviceById)
91 92 .collect(Collectors.toList())
92   - .forEach(device -> {
93   - try {
94   - establishDeviceSession(device);
95   - } catch (Exception e) {
96   - log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.getMessage());
97   - }
98   - });
  93 + .forEach(this::establishDeviceSession);
99 94 }
100 95
101 96 private void establishDeviceSession(Device device) {
102 97 if (device == null) return;
103   - log.info("Establishing SNMP device session for device {}", device.getId());
  98 + log.info("Establishing SNMP session for device {}", device.getId());
104 99
105 100 DeviceProfileId deviceProfileId = device.getDeviceProfileId();
106 101 DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
... ... @@ -114,19 +109,24 @@ public class SnmpTransportContext extends TransportContext {
114 109 SnmpDeviceProfileTransportConfiguration profileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
115 110 SnmpDeviceTransportConfiguration deviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
116 111
117   - DeviceSessionContext deviceSessionContext = new DeviceSessionContext(
118   - device, deviceProfile, credentials.getCredentialsId(),
119   - profileTransportConfiguration, deviceTransportConfiguration,
120   - this, snmpTransportService, snmpUnderlyingProtocol
121   - );
122   - registerSessionMsgListener(deviceSessionContext);
  112 + DeviceSessionContext deviceSessionContext;
  113 + try {
  114 + deviceSessionContext = new DeviceSessionContext(
  115 + device, deviceProfile, credentials.getCredentialsId(),
  116 + profileTransportConfiguration, deviceTransportConfiguration, this
  117 + );
  118 + registerSessionMsgListener(deviceSessionContext);
  119 + } catch (Exception e) {
  120 + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString());
  121 + return;
  122 + }
123 123 sessions.put(device.getId(), deviceSessionContext);
124 124 snmpTransportService.createQueryingTasks(deviceSessionContext);
125 125 log.info("Established SNMP device session for device {}", device.getId());
126 126 }
127 127
128 128 private void updateDeviceSession(DeviceSessionContext sessionContext, Device device, DeviceProfile deviceProfile) {
129   - log.info("Updating SNMP device session for device {}", device.getId());
  129 + log.info("Updating SNMP session for device {}", device.getId());
130 130
131 131 DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId());
132 132 if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) {
... ... @@ -138,16 +138,21 @@ public class SnmpTransportContext extends TransportContext {
138 138 SnmpDeviceProfileTransportConfiguration newProfileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
139 139 SnmpDeviceTransportConfiguration newDeviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
140 140
141   - if (!newProfileTransportConfiguration.equals(sessionContext.getProfileTransportConfiguration())) {
142   - sessionContext.setProfileTransportConfiguration(newProfileTransportConfiguration);
143   - sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
144   - snmpTransportService.cancelQueryingTasks(sessionContext);
145   - snmpTransportService.createQueryingTasks(sessionContext);
146   - } else if (!newDeviceTransportConfiguration.equals(sessionContext.getDeviceTransportConfiguration())) {
147   - sessionContext.setDeviceTransportConfiguration(newDeviceTransportConfiguration);
148   - sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
149   - } else {
150   - log.trace("Configuration of the device {} was not updated", device);
  141 + try {
  142 + if (!newProfileTransportConfiguration.equals(sessionContext.getProfileTransportConfiguration())) {
  143 + sessionContext.setProfileTransportConfiguration(newProfileTransportConfiguration);
  144 + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
  145 + snmpTransportService.cancelQueryingTasks(sessionContext);
  146 + snmpTransportService.createQueryingTasks(sessionContext);
  147 + } else if (!newDeviceTransportConfiguration.equals(sessionContext.getDeviceTransportConfiguration())) {
  148 + sessionContext.setDeviceTransportConfiguration(newDeviceTransportConfiguration);
  149 + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
  150 + } else {
  151 + log.trace("Configuration of the device {} was not updated", device);
  152 + }
  153 + } catch (Exception e) {
  154 + log.error("Failed to update session for SNMP device {}: {}", sessionContext.getDeviceId(), e.getMessage());
  155 + destroyDeviceSession(sessionContext);
151 156 }
152 157 }
153 158
... ... @@ -155,9 +160,10 @@ public class SnmpTransportContext extends TransportContext {
155 160 if (sessionContext == null) return;
156 161 log.info("Destroying SNMP device session for device {}", sessionContext.getDevice().getId());
157 162 sessionContext.close();
  163 + snmpAuthService.cleanUpSnmpAuthInfo(sessionContext);
158 164 transportService.deregisterSession(sessionContext.getSessionInfo());
159   - sessions.remove(sessionContext.getDeviceId());
160 165 snmpTransportService.cancelQueryingTasks(sessionContext);
  166 + sessions.remove(sessionContext.getDeviceId());
161 167 log.trace("Unregistered and removed session");
162 168 }
163 169
... ... @@ -173,7 +179,9 @@ public class SnmpTransportContext extends TransportContext {
173 179 );
174 180
175 181 transportService.registerAsyncSession(sessionInfo, deviceSessionContext);
176   - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
  182 + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY);
  183 + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY);
  184 +
177 185 deviceSessionContext.setSessionInfo(sessionInfo);
178 186 deviceSessionContext.setDeviceInfo(msg.getDeviceInfo());
179 187 } else {
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.snmp.service;
  17 +
  18 +import com.google.gson.JsonObject;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.snmp4j.PDU;
  21 +import org.snmp4j.ScopedPDU;
  22 +import org.snmp4j.smi.Integer32;
  23 +import org.snmp4j.smi.Null;
  24 +import org.snmp4j.smi.OID;
  25 +import org.snmp4j.smi.OctetString;
  26 +import org.snmp4j.smi.Variable;
  27 +import org.snmp4j.smi.VariableBinding;
  28 +import org.springframework.stereotype.Service;
  29 +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
  30 +import org.thingsboard.server.common.data.kv.DataType;
  31 +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
  32 +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod;
  33 +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
  34 +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig;
  35 +import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
  36 +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
  37 +
  38 +import java.util.HashMap;
  39 +import java.util.List;
  40 +import java.util.Map;
  41 +import java.util.Objects;
  42 +import java.util.Optional;
  43 +import java.util.stream.Collectors;
  44 +import java.util.stream.IntStream;
  45 +
  46 +@TbSnmpTransportComponent
  47 +@Service
  48 +@Slf4j
  49 +public class PduService {
  50 + public PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) {
  51 + PDU pdu = setUpPdu(sessionContext);
  52 +
  53 + pdu.setType(communicationConfig.getMethod().getCode());
  54 + pdu.addAll(communicationConfig.getAllMappings().stream()
  55 + .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey()))
  56 + .map(mapping -> Optional.ofNullable(values.get(mapping.getKey()))
  57 + .map(value -> {
  58 + Variable variable = toSnmpVariable(value, mapping.getDataType());
  59 + return new VariableBinding(new OID(mapping.getOid()), variable);
  60 + })
  61 + .orElseGet(() -> new VariableBinding(new OID(mapping.getOid()))))
  62 + .collect(Collectors.toList()));
  63 +
  64 + return pdu;
  65 + }
  66 +
  67 + public PDU createSingleVariablePdu(DeviceSessionContext sessionContext, SnmpMethod snmpMethod, String oid, String value, DataType dataType) {
  68 + PDU pdu = setUpPdu(sessionContext);
  69 + pdu.setType(snmpMethod.getCode());
  70 +
  71 + Variable variable = value == null ? Null.instance : toSnmpVariable(value, dataType);
  72 + pdu.add(new VariableBinding(new OID(oid), variable));
  73 +
  74 + return pdu;
  75 + }
  76 +
  77 + private Variable toSnmpVariable(String value, DataType dataType) {
  78 + dataType = dataType == null ? DataType.STRING : dataType;
  79 + Variable variable;
  80 + switch (dataType) {
  81 + case LONG:
  82 + try {
  83 + variable = new Integer32(Integer.parseInt(value));
  84 + break;
  85 + } catch (NumberFormatException ignored) {
  86 + }
  87 + case DOUBLE:
  88 + case BOOLEAN:
  89 + case STRING:
  90 + case JSON:
  91 + default:
  92 + variable = new OctetString(value);
  93 + }
  94 + return variable;
  95 + }
  96 +
  97 + private PDU setUpPdu(DeviceSessionContext sessionContext) {
  98 + PDU pdu;
  99 + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration();
  100 + SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion();
  101 + switch (snmpVersion) {
  102 + case V1:
  103 + case V2C:
  104 + pdu = new PDU();
  105 + break;
  106 + case V3:
  107 + ScopedPDU scopedPdu = new ScopedPDU();
  108 + scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName()));
  109 + scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId()));
  110 + pdu = scopedPdu;
  111 + break;
  112 + default:
  113 + throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported");
  114 + }
  115 + return pdu;
  116 + }
  117 +
  118 +
  119 + public JsonObject processPdu(PDU pdu, List<SnmpMapping> responseMappings) {
  120 + Map<OID, String> values = processPdu(pdu);
  121 +
  122 + Map<OID, SnmpMapping> mappings = new HashMap<>();
  123 + if (responseMappings != null) {
  124 + for (SnmpMapping mapping : responseMappings) {
  125 + OID oid = new OID(mapping.getOid());
  126 + mappings.put(oid, mapping);
  127 + }
  128 + }
  129 +
  130 + JsonObject data = new JsonObject();
  131 + values.forEach((oid, value) -> {
  132 + log.trace("Processing variable binding: {} - {}", oid, value);
  133 +
  134 + SnmpMapping mapping = mappings.get(oid);
  135 + if (mapping == null) {
  136 + log.debug("No SNMP mapping for oid {}", oid);
  137 + return;
  138 + }
  139 +
  140 + processValue(mapping.getKey(), mapping.getDataType(), value, data);
  141 + });
  142 +
  143 + return data;
  144 + }
  145 +
  146 + public Map<OID, String> processPdu(PDU pdu) {
  147 + return IntStream.range(0, pdu.size())
  148 + .mapToObj(pdu::get)
  149 + .filter(Objects::nonNull)
  150 + .filter(variableBinding -> !(variableBinding.getVariable() instanceof Null))
  151 + .collect(Collectors.toMap(VariableBinding::getOid, VariableBinding::toValueString));
  152 + }
  153 +
  154 + private void processValue(String key, DataType dataType, String value, JsonObject result) {
  155 + switch (dataType) {
  156 + case LONG:
  157 + result.addProperty(key, Long.parseLong(value));
  158 + break;
  159 + case BOOLEAN:
  160 + result.addProperty(key, Boolean.parseBoolean(value));
  161 + break;
  162 + case DOUBLE:
  163 + result.addProperty(key, Double.parseDouble(value));
  164 + break;
  165 + case STRING:
  166 + case JSON:
  167 + default:
  168 + result.addProperty(key, value);
  169 + }
  170 + }
  171 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.snmp.service;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import org.snmp4j.AbstractTarget;
  20 +import org.snmp4j.CommunityTarget;
  21 +import org.snmp4j.Target;
  22 +import org.snmp4j.UserTarget;
  23 +import org.snmp4j.security.SecurityLevel;
  24 +import org.snmp4j.security.SecurityModel;
  25 +import org.snmp4j.security.SecurityProtocols;
  26 +import org.snmp4j.security.USM;
  27 +import org.snmp4j.smi.Address;
  28 +import org.snmp4j.smi.GenericAddress;
  29 +import org.snmp4j.smi.OID;
  30 +import org.snmp4j.smi.OctetString;
  31 +import org.springframework.beans.factory.annotation.Value;
  32 +import org.springframework.stereotype.Service;
  33 +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
  35 +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
  36 +import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
  37 +import org.thingsboard.server.transport.snmp.service.SnmpTransportService;
  38 +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
  39 +
  40 +import java.util.Optional;
  41 +
  42 +@Service
  43 +@TbSnmpTransportComponent
  44 +@RequiredArgsConstructor
  45 +public class SnmpAuthService {
  46 + private final SnmpTransportService snmpTransportService;
  47 +
  48 + @Value("${transport.snmp.underlying_protocol}")
  49 + private String snmpUnderlyingProtocol;
  50 +
  51 + public Target setUpSnmpTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) {
  52 + AbstractTarget target;
  53 +
  54 + SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion();
  55 + switch (protocolVersion) {
  56 + case V1:
  57 + CommunityTarget communityTargetV1 = new CommunityTarget();
  58 + communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1);
  59 + communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
  60 + communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getCommunity()));
  61 + target = communityTargetV1;
  62 + break;
  63 + case V2C:
  64 + CommunityTarget communityTargetV2 = new CommunityTarget();
  65 + communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
  66 + communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
  67 + communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getCommunity()));
  68 + target = communityTargetV2;
  69 + break;
  70 + case V3:
  71 + OctetString username = new OctetString(deviceTransportConfig.getUsername());
  72 + OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName());
  73 + OctetString engineId = new OctetString(deviceTransportConfig.getEngineId());
  74 +
  75 + OID authenticationProtocol = new OID(deviceTransportConfig.getAuthenticationProtocol().getOid());
  76 + OID privacyProtocol = new OID(deviceTransportConfig.getPrivacyProtocol().getOid());
  77 + OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase());
  78 + authenticationPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(authenticationProtocol, authenticationPassphrase, engineId.getValue()));
  79 + OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase());
  80 + privacyPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(privacyProtocol, authenticationProtocol, privacyPassphrase, engineId.getValue()));
  81 +
  82 + USM usm = snmpTransportService.getSnmp().getUSM();
  83 + if (usm.hasUser(engineId, securityName)) {
  84 + usm.removeAllUsers(username, engineId);
  85 + }
  86 + usm.addLocalizedUser(
  87 + engineId.getValue(), username,
  88 + authenticationProtocol, authenticationPassphrase.getValue(),
  89 + privacyProtocol, privacyPassphrase.getValue()
  90 + );
  91 +
  92 + UserTarget userTarget = new UserTarget();
  93 + userTarget.setSecurityName(securityName);
  94 + userTarget.setAuthoritativeEngineID(engineId.getValue());
  95 + userTarget.setSecurityModel(SecurityModel.SECURITY_MODEL_USM);
  96 + userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
  97 + target = userTarget;
  98 + break;
  99 + default:
  100 + throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported");
  101 + }
  102 +
  103 + Address address = GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort());
  104 + target.setAddress(Optional.ofNullable(address).orElseThrow(() -> new IllegalArgumentException("Address of the SNMP device is invalid")));
  105 + target.setTimeout(profileTransportConfig.getTimeoutMs());
  106 + target.setRetries(profileTransportConfig.getRetries());
  107 + target.setVersion(protocolVersion.getCode());
  108 +
  109 + return target;
  110 + }
  111 +
  112 + public void cleanUpSnmpAuthInfo(DeviceSessionContext sessionContext) {
  113 + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration();
  114 + if (deviceTransportConfiguration.getProtocolVersion() == SnmpProtocolVersion.V3) {
  115 + OctetString username = new OctetString(deviceTransportConfiguration.getUsername());
  116 + OctetString engineId = new OctetString(deviceTransportConfiguration.getEngineId());
  117 + snmpTransportService.getSnmp().getUSM().removeAllUsers(username, engineId);
  118 + }
  119 + }
  120 +
  121 +}
... ...
... ... @@ -15,48 +15,46 @@
15 15 */
16 16 package org.thingsboard.server.transport.snmp.service;
17 17
  18 +import com.google.gson.JsonElement;
18 19 import com.google.gson.JsonObject;
  20 +import lombok.Data;
19 21 import lombok.Getter;
  22 +import lombok.RequiredArgsConstructor;
20 23 import lombok.extern.slf4j.Slf4j;
21   -import org.apache.commons.lang3.StringUtils;
22   -import org.snmp4j.CommandResponder;
23   -import org.snmp4j.CommandResponderEvent;
24 24 import org.snmp4j.PDU;
25 25 import org.snmp4j.Snmp;
26 26 import org.snmp4j.TransportMapping;
27 27 import org.snmp4j.event.ResponseEvent;
28   -import org.snmp4j.smi.Null;
29   -import org.snmp4j.smi.OID;
  28 +import org.snmp4j.mp.MPv3;
  29 +import org.snmp4j.security.SecurityModels;
  30 +import org.snmp4j.security.SecurityProtocols;
  31 +import org.snmp4j.security.USM;
30 32 import org.snmp4j.smi.OctetString;
31   -import org.snmp4j.smi.TcpAddress;
32   -import org.snmp4j.smi.UdpAddress;
33   -import org.snmp4j.smi.VariableBinding;
34 33 import org.snmp4j.transport.DefaultTcpTransportMapping;
35 34 import org.snmp4j.transport.DefaultUdpTransportMapping;
36 35 import org.springframework.beans.factory.annotation.Value;
37   -import org.springframework.context.annotation.Lazy;
38 36 import org.springframework.stereotype.Service;
39 37 import org.thingsboard.common.util.ThingsBoardThreadFactory;
40 38 import org.thingsboard.server.common.data.TbTransportService;
41   -import org.thingsboard.server.common.data.id.DeviceProfileId;
42 39 import org.thingsboard.server.common.data.kv.DataType;
43 40 import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
44 41 import org.thingsboard.server.common.data.transport.snmp.SnmpMapping;
45   -import org.thingsboard.server.common.data.transport.snmp.configs.RepeatingQueryingSnmpCommunicationConfig;
46   -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig;
  42 +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod;
  43 +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig;
  44 +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig;
47 45 import org.thingsboard.server.common.transport.TransportService;
48 46 import org.thingsboard.server.common.transport.TransportServiceCallback;
49 47 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
50 48 import org.thingsboard.server.gen.transport.TransportProtos;
51 49 import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
52   -import org.thingsboard.server.transport.snmp.SnmpTransportContext;
53 50 import org.thingsboard.server.transport.snmp.session.DeviceSessionContext;
54 51
55 52 import javax.annotation.PostConstruct;
56 53 import javax.annotation.PreDestroy;
57 54 import java.io.IOException;
  55 +import java.util.Arrays;
  56 +import java.util.Collections;
58 57 import java.util.EnumMap;
59   -import java.util.HashMap;
60 58 import java.util.List;
61 59 import java.util.Map;
62 60 import java.util.Optional;
... ... @@ -65,44 +63,36 @@ import java.util.concurrent.Executors;
65 63 import java.util.concurrent.ScheduledExecutorService;
66 64 import java.util.concurrent.ScheduledFuture;
67 65 import java.util.concurrent.TimeUnit;
68   -import java.util.function.BiConsumer;
69 66 import java.util.stream.Collectors;
70   -import java.util.stream.Stream;
71 67
72 68 @TbSnmpTransportComponent
73 69 @Service
74 70 @Slf4j
75   -public class SnmpTransportService implements TbTransportService, CommandResponder {
76   - private final SnmpTransportContext snmpTransportContext;
  71 +@RequiredArgsConstructor
  72 +public class SnmpTransportService implements TbTransportService {
77 73 private final TransportService transportService;
  74 + private final PduService pduService;
78 75
79 76 @Getter
80 77 private Snmp snmp;
81 78 private ScheduledExecutorService queryingExecutor;
82 79 private ExecutorService responseProcessingExecutor;
83 80
84   - private final Map<SnmpCommunicationSpec, BiConsumer<JsonObject, DeviceSessionContext>> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class);
  81 + private final Map<SnmpCommunicationSpec, ResponseDataMapper> responseDataMappers = new EnumMap<>(SnmpCommunicationSpec.class);
  82 + private final Map<SnmpCommunicationSpec, ResponseProcessor> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class);
85 83
86 84 @Value("${transport.snmp.response_processing.parallelism_level}")
87 85 private Integer responseProcessingParallelismLevel;
88 86 @Value("${transport.snmp.underlying_protocol}")
89 87 private String snmpUnderlyingProtocol;
90 88
91   - public SnmpTransportService(@Lazy SnmpTransportContext snmpTransportContext,
92   - TransportService transportService) {
93   - this.snmpTransportContext = snmpTransportContext;
94   - this.transportService = transportService;
95   - }
96   -
97 89 @PostConstruct
98 90 private void init() throws IOException {
99   - log.info("Initializing SNMP transport service");
100   -
101 91 queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying"));
102 92 responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel);
103 93
104 94 initializeSnmp();
105   - initializeTrapsListener();
  95 + configureResponseDataMappers();
106 96 configureResponseProcessors();
107 97
108 98 log.info("SNMP transport service initialized");
... ... @@ -122,53 +112,30 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
122 112 }
123 113 snmp = new Snmp(transportMapping);
124 114 snmp.listen();
125   - }
126   -
127   - private void initializeTrapsListener() throws IOException {
128   - int trapsListeningPort = 1062;
129   - String bindingAddress = "0.0.0.0/" + trapsListeningPort;
130 115
131   - TransportMapping<?> transportMapping;
132   - switch (snmpUnderlyingProtocol) {
133   - case "udp":
134   - transportMapping = new DefaultUdpTransportMapping(new UdpAddress(bindingAddress));
135   - break;
136   - case "tcp":
137   - transportMapping = new DefaultTcpTransportMapping(new TcpAddress(bindingAddress));
138   - break;
139   - default:
140   - throw new IllegalArgumentException("Underlying protocol " + snmpUnderlyingProtocol + " for SNMP is not supported");
141   - }
142   -
143   -
144   - Snmp trapsSnmp = new Snmp(transportMapping);
145   - trapsSnmp.addCommandResponder(this);
146   -
147   - transportMapping.listen();
  116 + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
  117 + SecurityModels.getInstance().addSecurityModel(usm);
148 118 }
149 119
150 120 public void createQueryingTasks(DeviceSessionContext sessionContext) {
151 121 List<ScheduledFuture<?>> queryingTasks = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream()
152   - .filter(config -> config.getSpec().isRepeatingQuerying())
  122 + .filter(communicationConfig -> communicationConfig instanceof RepeatingQueryingSnmpCommunicationConfig)
153 123 .map(config -> {
154 124 RepeatingQueryingSnmpCommunicationConfig repeatingCommunicationConfig = (RepeatingQueryingSnmpCommunicationConfig) config;
155   - return createQueryingTaskForConfig(sessionContext, repeatingCommunicationConfig);
  125 + Long queryingFrequency = repeatingCommunicationConfig.getQueryingFrequencyMs();
  126 +
  127 + return queryingExecutor.scheduleWithFixedDelay(() -> {
  128 + try {
  129 + if (sessionContext.isActive()) {
  130 + sendRequest(sessionContext, repeatingCommunicationConfig);
  131 + }
  132 + } catch (Exception e) {
  133 + log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString());
  134 + }
  135 + }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS);
156 136 })
157 137 .collect(Collectors.toList());
158   - sessionContext.setQueryingTasks(queryingTasks);
159   - }
160   -
161   - private ScheduledFuture<?> createQueryingTaskForConfig(DeviceSessionContext sessionContext, RepeatingQueryingSnmpCommunicationConfig communicationConfig) {
162   - Long queryingFrequency = communicationConfig.getQueryingFrequencyMs();
163   - return queryingExecutor.scheduleWithFixedDelay(() -> {
164   - try {
165   - if (sessionContext.isActive()) {
166   - sendRequest(sessionContext, communicationConfig);
167   - }
168   - } catch (Exception e) {
169   - log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.getMessage());
170   - }
171   - }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS);
  138 + sessionContext.getQueryingTasks().addAll(queryingTasks);
172 139 }
173 140
174 141 public void cancelQueryingTasks(DeviceSessionContext sessionContext) {
... ... @@ -176,187 +143,146 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
176 143 sessionContext.getQueryingTasks().clear();
177 144 }
178 145
179   - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) throws IOException {
180   - PDU request = createPdu(communicationConfig);
181   - executeRequest(sessionContext, request);
  146 +
  147 + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) {
  148 + sendRequest(sessionContext, communicationConfig, Collections.emptyMap());
182 149 }
183 150
184   - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) throws IOException {
185   - PDU request = createPduWithValues(communicationConfig, values);
186   - executeRequest(sessionContext, request);
  151 + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) {
  152 + PDU request = pduService.createPdu(sessionContext, communicationConfig, values);
  153 + RequestInfo requestInfo = new RequestInfo(communicationConfig.getSpec(), communicationConfig.getAllMappings());
  154 + sendRequest(sessionContext, request, requestInfo);
187 155 }
188 156
189   - private void executeRequest(DeviceSessionContext sessionContext, PDU request) throws IOException {
  157 + private void sendRequest(DeviceSessionContext sessionContext, PDU request, RequestInfo requestInfo) {
190 158 if (request.size() > 0) {
191 159 log.trace("Executing SNMP request for device {}. Variables bindings: {}", sessionContext.getDeviceId(), request.getVariableBindings());
192   - snmp.send(request, sessionContext.getTarget(), sessionContext.getDeviceProfile().getId(), sessionContext);
  160 + try {
  161 + snmp.send(request, sessionContext.getTarget(), requestInfo, sessionContext);
  162 + } catch (IOException e) {
  163 + log.error("Failed to send SNMP request to device {}: {}", sessionContext.getDeviceId(), e.toString());
  164 + }
193 165 }
194 166 }
195 167
196   - private PDU createPdu(SnmpCommunicationConfig communicationConfig) {
197   - PDU pdu = new PDU();
198   - pdu.setType(communicationConfig.getMethod().getCode());
199   - pdu.addAll(communicationConfig.getMappings().stream()
200   - .map(mapping -> new VariableBinding(new OID(mapping.getOid())))
201   - .collect(Collectors.toList()));
202   - return pdu;
  168 + public void onAttributeUpdate(DeviceSessionContext sessionContext, TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification) {
  169 + sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream()
  170 + .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING)
  171 + .findFirst()
  172 + .ifPresent(communicationConfig -> {
  173 + Map<String, String> sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream()
  174 + .collect(Collectors.toMap(
  175 + Map.Entry::getKey,
  176 + entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString()
  177 + ));
  178 + sendRequest(sessionContext, communicationConfig, sharedAttributes);
  179 + });
203 180 }
204 181
205   - private PDU createPduWithValues(SnmpCommunicationConfig communicationConfig, Map<String, String> values) {
206   - PDU pdu = new PDU();
207   - pdu.setType(communicationConfig.getMethod().getCode());
208   - pdu.addAll(communicationConfig.getMappings().stream()
209   - .filter(mapping -> values.containsKey(mapping.getKey()))
210   - .map(mapping -> {
211   - String value = values.get(mapping.getKey());
212   - return new VariableBinding(new OID(mapping.getOid()), new OctetString(value));
213   - })
214   - .collect(Collectors.toList()));
215   - return pdu;
216   - }
  182 + public void onToDeviceRpcRequest(DeviceSessionContext sessionContext, TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg) {
  183 + SnmpMethod snmpMethod = SnmpMethod.valueOf(toDeviceRpcRequestMsg.getMethodName());
  184 + JsonObject params = JsonConverter.parse(toDeviceRpcRequestMsg.getParams()).getAsJsonObject();
217 185
  186 + String oid = Optional.ofNullable(params.get("oid")).map(JsonElement::getAsString).orElse(null);
  187 + String value = Optional.ofNullable(params.get("value")).map(JsonElement::getAsString).orElse(null);
  188 + DataType dataType = Optional.ofNullable(params.get("dataType")).map(e -> DataType.valueOf(e.getAsString())).orElse(DataType.STRING);
218 189
219   - private void processTrap(CommandResponderEvent event) {
220   - if (event.getPDU().getType() != PDU.TRAP) return;
  190 + if (oid == null || oid.isEmpty()) {
  191 + throw new IllegalArgumentException("OID in to-device RPC request is not specified");
  192 + }
  193 + if (value == null && snmpMethod == SnmpMethod.SET) {
  194 + throw new IllegalArgumentException("Value must be specified for SNMP method 'SET'");
  195 + }
221 196
222   - snmpTransportContext.getSessions().stream()
223   - .filter(sessionContext -> {
224   - // TODO: SNMP v3 support
225   - return sessionContext.getTarget().getSecurityName().equals(OctetString.fromByteArray(event.getSecurityName())) &&
226   - sessionContext.getTarget().getAddress().equals(event.getPeerAddress());
227   - })
228   - .findFirst()
229   - .ifPresentOrElse(sessionContext -> {
230   - responseProcessingExecutor.execute(() -> processResponse(sessionContext, event.getPDU()));
231   - }, () -> {
232   - log.debug("SNMP event is from unknown source: {}", event);
233   - });
  197 + PDU request = pduService.createSingleVariablePdu(sessionContext, snmpMethod, oid, value, dataType);
  198 + sendRequest(sessionContext, request, new RequestInfo(toDeviceRpcRequestMsg.getRequestId(), SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST));
234 199 }
235 200
  201 +
236 202 public void processResponseEvent(DeviceSessionContext sessionContext, ResponseEvent event) {
237 203 ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext);
238 204
239 205 if (event.getError() != null) {
240   - log.warn("Response error: {}", event.getError().getMessage(), event.getError());
  206 + log.warn("SNMP response error: {}", event.getError().toString());
241 207 return;
242 208 }
243 209
244 210 PDU response = event.getResponse();
245 211 if (response == null) {
246   - log.warn("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID());
  212 + log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID());
247 213 return;
248 214 }
249   - DeviceProfileId deviceProfileId = (DeviceProfileId) event.getUserObject();
250   - log.debug("[{}] Processing SNMP response for device {} with device profile {}: {}",
251   - response.getRequestID(), sessionContext.getDeviceId(), deviceProfileId, response);
252 215
253   - responseProcessingExecutor.execute(() -> processResponse(sessionContext, response));
  216 + RequestInfo requestInfo = (RequestInfo) event.getUserObject();
  217 + responseProcessingExecutor.execute(() -> {
  218 + processResponse(sessionContext, response, requestInfo);
  219 + });
254 220 }
255 221
256   - private void processResponse(DeviceSessionContext sessionContext, PDU responsePdu) {
257   - Map<OID, SnmpMapping> mappings = new HashMap<>();
258   - Map<OID, SnmpCommunicationConfig> configs = new HashMap<>();
259   - Map<SnmpCommunicationSpec, JsonObject> responses = new EnumMap<>(SnmpCommunicationSpec.class);
  222 + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) {
  223 + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationSpec());
  224 + if (responseProcessor == null) return;
260 225
261   - for (SnmpCommunicationConfig config : sessionContext.getProfileTransportConfiguration().getCommunicationConfigs()) {
262   - for (SnmpMapping mapping : config.getMappings()) {
263   - OID oid = new OID(mapping.getOid());
264   - mappings.put(oid, mapping);
265   - configs.put(oid, config);
266   - }
267   - responses.put(config.getSpec(), new JsonObject());
268   - }
269   -
270   - for (int i = 0; i < responsePdu.size(); i++) {
271   - VariableBinding variableBinding = responsePdu.get(i);
272   - log.trace("Processing variable binding {}: {}", i, variableBinding);
273   -
274   - if (variableBinding.getVariable() instanceof Null) {
275   - log.debug("Response variable is empty");
276   - continue;
277   - }
  226 + JsonObject responseData = responseDataMappers.get(requestInfo.getCommunicationSpec()).map(response, requestInfo);
278 227
279   - OID oid = variableBinding.getOid();
280   - if (!mappings.containsKey(oid)) {
281   - log.debug("No SNMP mapping for oid {}", oid);
282   - continue;
283   - }
284   -
285   - SnmpCommunicationSpec spec = configs.get(oid).getSpec();
286   - if (!responseProcessors.containsKey(spec)) {
287   - log.debug("No response processor found for spec {}", spec);
288   - continue;
289   - }
290   -
291   - SnmpMapping mapping = mappings.get(oid);
292   - processValue(mapping.getKey(), mapping.getDataType(), variableBinding.toValueString(), responses.get(spec));
293   - }
294   -
295   - if (responses.values().stream().allMatch(response -> response.entrySet().isEmpty())) {
296   - log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), responsePdu.getRequestID());
  228 + if (responseData.entrySet().isEmpty()) {
  229 + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID());
297 230 return;
298 231 }
299 232
300   - responses.forEach((spec, response) -> {
301   - Optional.ofNullable(responseProcessors.get(spec))
302   - .ifPresent(responseProcessor -> {
303   - responseProcessor.accept(response, sessionContext);
304   - });
  233 + responseProcessor.process(responseData, requestInfo, sessionContext);
  234 + reportActivity(sessionContext.getSessionInfo());
  235 + }
  236 +
  237 + private void configureResponseDataMappers() {
  238 + responseDataMappers.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (pdu, requestInfo) -> {
  239 + JsonObject responseData = new JsonObject();
  240 + pduService.processPdu(pdu).forEach((oid, value) -> {
  241 + responseData.addProperty(oid.toDottedString(), value);
  242 + });
  243 + return responseData;
305 244 });
306 245
307   - reportActivity(sessionContext.getSessionInfo());
  246 + ResponseDataMapper defaultResponseDataMapper = (pdu, requestInfo) -> {
  247 + return pduService.processPdu(pdu, requestInfo.getResponseMappings());
  248 + };
  249 + Arrays.stream(SnmpCommunicationSpec.values())
  250 + .forEach(communicationSpec -> {
  251 + responseDataMappers.putIfAbsent(communicationSpec, defaultResponseDataMapper);
  252 + });
308 253 }
309 254
310 255 private void configureResponseProcessors() {
311   - Stream.of(SnmpCommunicationSpec.TELEMETRY_QUERYING, SnmpCommunicationSpec.TELEMETRY_TRAPS_RECEIVING)
312   - .forEach(telemetrySpec -> {
313   - responseProcessors.put(telemetrySpec, (response, sessionContext) -> {
314   - TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(response);
315   - transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, TransportServiceCallback.EMPTY);
316   - log.debug("Posted telemetry for device {}: {}", sessionContext.getDeviceId(), response);
317   - });
318   - });
  256 + responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (responseData, requestInfo, sessionContext) -> {
  257 + TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(responseData);
  258 + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null);
  259 + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), responseData);
  260 + });
319 261
320   - Stream.of(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, SnmpCommunicationSpec.CLIENT_ATTRIBUTES_TRAPS_RECEIVING)
321   - .forEach(clientAttributesSpec -> {
322   - responseProcessors.put(clientAttributesSpec, (response, sessionContext) -> {
323   - TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(response);
324   - transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, TransportServiceCallback.EMPTY);
325   - log.debug("Posted attributes for device {}: {}", sessionContext.getDeviceId(), response);
326   - });
327   - });
  262 + responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (responseData, requestInfo, sessionContext) -> {
  263 + TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(responseData);
  264 + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null);
  265 + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), responseData);
  266 + });
  267 +
  268 + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (responseData, requestInfo, sessionContext) -> {
  269 + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  270 + .setRequestId(requestInfo.getRequestId())
  271 + .setPayload(JsonConverter.toJson(responseData))
  272 + .build();
  273 + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null);
  274 + log.debug("Posted RPC response {} for device {}", responseData, sessionContext.getDeviceId());
  275 + });
328 276 }
329 277
330 278 private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) {
331 279 transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
332   - .setAttributeSubscription(false)
333   - .setRpcSubscription(false)
  280 + .setAttributeSubscription(true)
  281 + .setRpcSubscription(true)
334 282 .setLastActivityTime(System.currentTimeMillis())
335 283 .build(), TransportServiceCallback.EMPTY);
336 284 }
337 285
338   - private void processValue(String key, DataType dataType, String value, JsonObject result) {
339   - if (StringUtils.isEmpty(value)) return;
340   -
341   - switch (dataType) {
342   - case LONG:
343   - result.addProperty(key, Long.parseLong(value));
344   - break;
345   - case BOOLEAN:
346   - result.addProperty(key, Boolean.parseBoolean(value));
347   - break;
348   - case DOUBLE:
349   - result.addProperty(key, Double.parseDouble(value));
350   - break;
351   - default:
352   - result.addProperty(key, value);
353   - }
354   - }
355   -
356   - @Override
357   - public void processPdu(CommandResponderEvent event) {
358   - processTrap(event);
359   - }
360 286
361 287 @Override
362 288 public String getName() {
... ... @@ -381,4 +307,34 @@ public class SnmpTransportService implements TbTransportService, CommandResponde
381 307 }
382 308 log.info("SNMP transport stopped!");
383 309 }
  310 +
  311 + @Data
  312 + private static class RequestInfo {
  313 + private Integer requestId;
  314 + private SnmpCommunicationSpec communicationSpec;
  315 + private List<SnmpMapping> responseMappings;
  316 +
  317 + public RequestInfo(Integer requestId, SnmpCommunicationSpec communicationSpec) {
  318 + this.requestId = requestId;
  319 + this.communicationSpec = communicationSpec;
  320 + }
  321 +
  322 + public RequestInfo(SnmpCommunicationSpec communicationSpec) {
  323 + this.communicationSpec = communicationSpec;
  324 + }
  325 +
  326 + public RequestInfo(SnmpCommunicationSpec communicationSpec, List<SnmpMapping> responseMappings) {
  327 + this.communicationSpec = communicationSpec;
  328 + this.responseMappings = responseMappings;
  329 + }
  330 + }
  331 +
  332 + private interface ResponseDataMapper {
  333 + JsonObject map(PDU pdu, RequestInfo requestInfo);
  334 + }
  335 +
  336 + private interface ResponseProcessor {
  337 + void process(JsonObject responseData, RequestInfo requestInfo, DeviceSessionContext sessionContext);
  338 + }
  339 +
384 340 }
... ...
... ... @@ -18,31 +18,15 @@ package org.thingsboard.server.transport.snmp.session;
18 18 import lombok.Getter;
19 19 import lombok.Setter;
20 20 import lombok.extern.slf4j.Slf4j;
21   -import org.snmp4j.AbstractTarget;
22   -import org.snmp4j.CommunityTarget;
23 21 import org.snmp4j.Target;
24   -import org.snmp4j.UserTarget;
25 22 import org.snmp4j.event.ResponseEvent;
26 23 import org.snmp4j.event.ResponseListener;
27   -import org.snmp4j.security.AuthSHA;
28   -import org.snmp4j.security.PrivDES;
29   -import org.snmp4j.security.SecurityLevel;
30   -import org.snmp4j.security.SecurityModel;
31   -import org.snmp4j.security.SecurityModels;
32   -import org.snmp4j.security.USM;
33   -import org.snmp4j.security.UsmUser;
34   -import org.snmp4j.smi.GenericAddress;
35   -import org.snmp4j.smi.OID;
36   -import org.snmp4j.smi.OctetString;
37 24 import org.thingsboard.server.common.data.Device;
38 25 import org.thingsboard.server.common.data.DeviceProfile;
39 26 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
40 27 import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
41 28 import org.thingsboard.server.common.data.id.DeviceId;
42   -import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec;
43   -import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion;
44 29 import org.thingsboard.server.common.transport.SessionMsgListener;
45   -import org.thingsboard.server.common.transport.adaptor.JsonConverter;
46 30 import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
47 31 import org.thingsboard.server.gen.transport.TransportProtos;
48 32 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
... ... @@ -51,15 +35,12 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotifica
51 35 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
52 36 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
53 37 import org.thingsboard.server.transport.snmp.SnmpTransportContext;
54   -import org.thingsboard.server.transport.snmp.service.SnmpTransportService;
55 38
56 39 import java.util.LinkedList;
57 40 import java.util.List;
58   -import java.util.Map;
59 41 import java.util.UUID;
60 42 import java.util.concurrent.ScheduledFuture;
61 43 import java.util.concurrent.atomic.AtomicInteger;
62   -import java.util.stream.Collectors;
63 44
64 45 @Slf4j
65 46 public class DeviceSessionContext extends DeviceAwareSessionContext implements SessionMsgListener, ResponseListener {
... ... @@ -76,25 +57,18 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
76 57 private final Device device;
77 58
78 59 private final SnmpTransportContext snmpTransportContext;
79   - private final SnmpTransportService snmpTransportService;
80 60
81   - @Getter
82   - @Setter
83   - private long previousRequestExecutedAt = 0;
84 61 private final AtomicInteger msgIdSeq = new AtomicInteger(0);
85 62 @Getter
86 63 private boolean isActive = true;
87   - private final String snmpUnderlyingProtocol;
88 64
89 65 @Getter
90   - @Setter
91   - private List<ScheduledFuture<?>> queryingTasks = new LinkedList<>();
  66 + private final List<ScheduledFuture<?>> queryingTasks = new LinkedList<>();
92 67
93 68 public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token,
94 69 SnmpDeviceProfileTransportConfiguration profileTransportConfiguration,
95 70 SnmpDeviceTransportConfiguration deviceTransportConfiguration,
96   - SnmpTransportContext snmpTransportContext, SnmpTransportService snmpTransportService,
97   - String snmpUnderlyingProtocol) {
  71 + SnmpTransportContext snmpTransportContext) throws Exception {
98 72 super(UUID.randomUUID());
99 73 super.setDeviceId(device.getId());
100 74 super.setDeviceProfile(deviceProfile);
... ... @@ -102,12 +76,10 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
102 76
103 77 this.token = token;
104 78 this.snmpTransportContext = snmpTransportContext;
105   - this.snmpTransportService = snmpTransportService;
106 79
107 80 this.profileTransportConfiguration = profileTransportConfiguration;
108 81 this.deviceTransportConfiguration = deviceTransportConfiguration;
109 82
110   - this.snmpUnderlyingProtocol = snmpUnderlyingProtocol;
111 83 initializeTarget(profileTransportConfiguration, deviceTransportConfiguration);
112 84 }
113 85
... ... @@ -127,62 +99,14 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
127 99 @Override
128 100 public void onResponse(ResponseEvent event) {
129 101 if (isActive) {
130   - snmpTransportService.processResponseEvent(this, event);
  102 + snmpTransportContext.getSnmpTransportService().processResponseEvent(this, event);
131 103 }
132 104 }
133 105
134   - public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) {
  106 + public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) throws Exception {
135 107 log.trace("Initializing target for SNMP session of device {}", device);
136   -
137   - AbstractTarget target;
138   -
139   - SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion();
140   - switch (protocolVersion) {
141   - case V1:
142   - CommunityTarget communityTargetV1 = new CommunityTarget();
143   - communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1);
144   - communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
145   - communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getSecurityName()));
146   - target = communityTargetV1;
147   - break;
148   - case V2C:
149   - CommunityTarget communityTargetV2 = new CommunityTarget();
150   - communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
151   - communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
152   - communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getSecurityName()));
153   - target = communityTargetV2;
154   - break;
155   - case V3:
156   - USM usm = new USM();
157   - SecurityModels.getInstance().addSecurityModel(usm);
158   -
159   - OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName());
160   - OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase());
161   - OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase());
162   -
163   - OID authenticationProtocol = AuthSHA.ID;
164   - OID privacyProtocol = PrivDES.ID; // FIXME: to config
165   -
166   - UsmUser user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase);
167   - snmpTransportService.getSnmp().getUSM().addUser(user);
168   -
169   - UserTarget userTarget = new UserTarget();
170   - userTarget.setSecurityName(securityName);
171   - userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
172   -
173   - target = userTarget;
174   - break;
175   - default:
176   - throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported");
177   - }
178   -
179   - target.setAddress(GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getAddress() + "/" + deviceTransportConfig.getPort()));
180   - target.setTimeout(profileTransportConfig.getTimeoutMs());
181   - target.setRetries(profileTransportConfig.getRetries());
182   - target.setVersion(protocolVersion.getCode());
183   -
184   - this.target = target;
185   - log.info("SNMP target initialized: {}", target);
  108 + this.target = snmpTransportContext.getSnmpAuthService().setUpSnmpTarget(profileTransportConfig, deviceTransportConfig);
  109 + log.debug("SNMP target initialized: {}", target);
186 110 }
187 111
188 112 public void close() {
... ... @@ -204,21 +128,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
204 128
205 129 @Override
206 130 public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) {
207   - profileTransportConfiguration.getCommunicationConfigs().stream()
208   - .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING)
209   - .findFirst()
210   - .ifPresent(communicationConfig -> {
211   - Map<String, String> sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream()
212   - .collect(Collectors.toMap(
213   - Map.Entry::getKey,
214   - entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString()
215   - ));
216   - try {
217   - snmpTransportService.sendRequest(this, communicationConfig, sharedAttributes);
218   - } catch (Exception e) {
219   - log.error("Failed to send request with shared attributes to SNMP device {}: {}", getDeviceId(), e.getMessage());
220   - }
221   - });
  131 + snmpTransportContext.getSnmpTransportService().onAttributeUpdate(this, attributeUpdateNotification);
222 132 }
223 133
224 134 @Override
... ... @@ -227,6 +137,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
227 137
228 138 @Override
229 139 public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
  140 + snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest);
230 141 }
231 142
232 143 @Override
... ...
... ... @@ -73,32 +73,6 @@ public class SnmpDeviceSimulatorV2 extends BaseAgent {
73 73 }
74 74 }
75 75
76   - public static void main(String[] args) throws IOException {
77   - SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public");
78   -
79   - device.start();
80   - device.setUpMappings(Map.of(
81   - ".1.3.6.1.2.1.1.1.50", "12",
82   - ".1.3.6.1.2.1.2.1.52", "56",
83   - ".1.3.6.1.2.1.3.1.54", "yes",
84   - ".1.3.6.1.2.1.7.1.58", ""
85   - ));
86   -
87   -
88   -// while (true) {
89   -// new Scanner(System.in).nextLine();
90   -// device.sendTrap("127.0.0.1", 1062, Map.of(".1.3.6.1.2.87.1.56", "12"));
91   -// System.out.println("sent");
92   -// }
93   -
94   -// Snmp snmp = new Snmp(device.transportMappings[0]);
95   -// device.snmp.addCommandResponder(event -> {
96   -// System.out.println(event);
97   -// });
98   -
99   - new Scanner(System.in).nextLine();
100   - }
101   -
102 76
103 77 private final Target target;
104 78 private final Address address;
... ...
... ... @@ -15,38 +15,731 @@
15 15 */
16 16 package org.thingsboard.server.transport.snmp;
17 17
18   -import org.snmp4j.UserTarget;
  18 +import org.snmp4j.MessageDispatcherImpl;
  19 +import org.snmp4j.TransportMapping;
  20 +import org.snmp4j.agent.BaseAgent;
  21 +import org.snmp4j.agent.CommandProcessor;
  22 +import org.snmp4j.agent.DuplicateRegistrationException;
  23 +import org.snmp4j.agent.MOGroup;
  24 +import org.snmp4j.agent.ManagedObject;
  25 +import org.snmp4j.agent.mo.DefaultMOMutableRow2PC;
  26 +import org.snmp4j.agent.mo.DefaultMOTable;
  27 +import org.snmp4j.agent.mo.MOAccessImpl;
  28 +import org.snmp4j.agent.mo.MOColumn;
  29 +import org.snmp4j.agent.mo.MOMutableColumn;
  30 +import org.snmp4j.agent.mo.MOMutableTableModel;
  31 +import org.snmp4j.agent.mo.MOScalar;
  32 +import org.snmp4j.agent.mo.MOTableIndex;
  33 +import org.snmp4j.agent.mo.MOTableRow;
  34 +import org.snmp4j.agent.mo.MOTableSubIndex;
  35 +import org.snmp4j.agent.mo.ext.AgentppSimulationMib;
  36 +import org.snmp4j.agent.mo.snmp.RowStatus;
  37 +import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
  38 +import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
  39 +import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
  40 +import org.snmp4j.agent.mo.snmp.StorageType;
  41 +import org.snmp4j.agent.mo.snmp.TransportDomains;
  42 +import org.snmp4j.agent.mo.snmp.VacmMIB;
  43 +import org.snmp4j.agent.mo.snmp4j.example.Snmp4jHeartbeatMib;
  44 +import org.snmp4j.agent.security.MutableVACM;
  45 +import org.snmp4j.mp.MPv1;
  46 +import org.snmp4j.mp.MPv2c;
  47 +import org.snmp4j.mp.MPv3;
  48 +import org.snmp4j.mp.MessageProcessingModel;
  49 +import org.snmp4j.security.AuthHMAC192SHA256;
  50 +import org.snmp4j.security.AuthMD5;
19 51 import org.snmp4j.security.AuthSHA;
  52 +import org.snmp4j.security.PrivAES128;
  53 +import org.snmp4j.security.PrivAES192;
  54 +import org.snmp4j.security.PrivAES256;
20 55 import org.snmp4j.security.PrivDES;
21 56 import org.snmp4j.security.SecurityLevel;
  57 +import org.snmp4j.security.SecurityModel;
22 58 import org.snmp4j.security.SecurityModels;
  59 +import org.snmp4j.security.SecurityProtocols;
23 60 import org.snmp4j.security.USM;
24 61 import org.snmp4j.security.UsmUser;
  62 +import org.snmp4j.smi.Address;
  63 +import org.snmp4j.smi.Gauge32;
  64 +import org.snmp4j.smi.GenericAddress;
  65 +import org.snmp4j.smi.Integer32;
25 66 import org.snmp4j.smi.OID;
26 67 import org.snmp4j.smi.OctetString;
  68 +import org.snmp4j.smi.SMIConstants;
  69 +import org.snmp4j.smi.TcpAddress;
  70 +import org.snmp4j.smi.TimeTicks;
  71 +import org.snmp4j.smi.UdpAddress;
  72 +import org.snmp4j.smi.Variable;
  73 +import org.snmp4j.transport.DefaultTcpTransportMapping;
  74 +import org.snmp4j.transport.TransportMappings;
  75 +import org.snmp4j.util.ThreadPool;
27 76
  77 +import java.io.File;
28 78 import java.io.IOException;
  79 +import java.util.Map;
29 80
30   -public class SnmpDeviceSimulatorV3 extends SnmpDeviceSimulatorV2 {
31   - public SnmpDeviceSimulatorV3(int port, String securityName, String authenticationPassphrase, String privacyPassphrase) throws IOException {
32   - super(12, null);
33   -// super(new File("conf.agent"), new File("bootCounter.agent"));
  81 +/**
  82 + * The TestAgent is a sample SNMP agent implementation of all
  83 + * features (MIB implementations) provided by the SNMP4J-Agent framework.
  84 + *
  85 + * Note, for snmp4s, this code is mostly a copy from snmp4j.
  86 + * And don't remove snmp users
  87 + *
  88 + */
  89 +public class SnmpDeviceSimulatorV3 extends BaseAgent {
  90 + protected String address;
  91 + private Snmp4jHeartbeatMib heartbeatMIB;
  92 + private AgentppSimulationMib agentppSimulationMIB;
  93 +
  94 + public SnmpDeviceSimulatorV3(CommandProcessor processor) throws IOException {
  95 + super(new File("SNMP4JTestAgentBC.cfg"), new File("SNMP4JTestAgentConfig.cfg"),
  96 + processor);
  97 + agent.setWorkerPool(ThreadPool.create("RequestPool", 4));
  98 + }
  99 +
  100 + public void setUpMappings(Map<String, String> oidToResponseMappings) {
  101 + unregisterManagedObject(getSnmpv2MIB());
  102 + oidToResponseMappings.forEach((oid, response) -> {
  103 + registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response)));
  104 + });
  105 + }
  106 + protected void registerManagedObject(ManagedObject mo) {
  107 + try {
  108 + server.register(mo, null);
  109 + } catch (DuplicateRegistrationException ex) {
  110 + throw new RuntimeException(ex);
  111 + }
  112 + }
  113 +
  114 + protected void unregisterManagedObject(MOGroup moGroup) {
  115 + moGroup.unregisterMOs(server, getContext(moGroup));
  116 + }
  117 +
  118 + protected void registerManagedObjects() {
  119 + try {
  120 + server.register(createStaticIfTable(), null);
  121 + server.register(createStaticIfXTable(), null);
  122 + agentppSimulationMIB.registerMOs(server, null);
  123 + heartbeatMIB.registerMOs(server, null);
  124 + } catch (DuplicateRegistrationException ex) {
  125 + ex.printStackTrace();
  126 + }
  127 + }
  128 +
  129 + protected void addNotificationTargets(SnmpTargetMIB targetMIB,
  130 + SnmpNotificationMIB notificationMIB) {
  131 + targetMIB.addDefaultTDomains();
  132 +
  133 + targetMIB.addTargetAddress(new OctetString("notificationV2c"),
  134 + TransportDomains.transportDomainUdpIpv4,
  135 + new OctetString(new UdpAddress("127.0.0.1/162").getValue()),
  136 + 200, 1,
  137 + new OctetString("notify"),
  138 + new OctetString("v2c"),
  139 + StorageType.permanent);
  140 + targetMIB.addTargetAddress(new OctetString("notificationV3"),
  141 + TransportDomains.transportDomainUdpIpv4,
  142 + new OctetString(new UdpAddress("127.0.0.1/1162").getValue()),
  143 + 200, 1,
  144 + new OctetString("notify"),
  145 + new OctetString("v3notify"),
  146 + StorageType.permanent);
  147 + targetMIB.addTargetParams(new OctetString("v2c"),
  148 + MessageProcessingModel.MPv2c,
  149 + SecurityModel.SECURITY_MODEL_SNMPv2c,
  150 + new OctetString("cpublic"),
  151 + SecurityLevel.AUTH_PRIV,
  152 + StorageType.permanent);
  153 + targetMIB.addTargetParams(new OctetString("v3notify"),
  154 + MessageProcessingModel.MPv3,
  155 + SecurityModel.SECURITY_MODEL_USM,
  156 + new OctetString("v3notify"),
  157 + SecurityLevel.NOAUTH_NOPRIV,
  158 + StorageType.permanent);
  159 + notificationMIB.addNotifyEntry(new OctetString("default"),
  160 + new OctetString("notify"),
  161 + SnmpNotificationMIB.SnmpNotifyTypeEnum.inform,
  162 + StorageType.permanent);
  163 + }
  164 + protected void addViews(VacmMIB vacm) {
  165 + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1,
  166 + new OctetString("cpublic"),
  167 + new OctetString("v1v2group"),
  168 + StorageType.nonVolatile);
  169 + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c,
  170 + new OctetString("cpublic"),
  171 + new OctetString("v1v2group"),
  172 + StorageType.nonVolatile);
  173 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  174 + new OctetString("SHADES"),
  175 + new OctetString("v3group"),
  176 + StorageType.nonVolatile);
  177 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  178 + new OctetString("MD5DES"),
  179 + new OctetString("v3group"),
  180 + StorageType.nonVolatile);
  181 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  182 + new OctetString("TEST"),
  183 + new OctetString("v3test"),
  184 + StorageType.nonVolatile);
  185 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  186 + new OctetString("SHA"),
  187 + new OctetString("v3restricted"),
  188 + StorageType.nonVolatile);
  189 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  190 + new OctetString("SHAAES128"),
  191 + new OctetString("v3group"),
  192 + StorageType.nonVolatile);
  193 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  194 + new OctetString("SHAAES192"),
  195 + new OctetString("v3group"),
  196 + StorageType.nonVolatile);
  197 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  198 + new OctetString("SHAAES256"),
  199 + new OctetString("v3group"),
  200 + StorageType.nonVolatile);
  201 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  202 + new OctetString("MD5AES128"),
  203 + new OctetString("v3group"),
  204 + StorageType.nonVolatile);
  205 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  206 + new OctetString("MD5AES192"),
  207 + new OctetString("v3group"),
  208 + StorageType.nonVolatile);
  209 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  210 + new OctetString("MD5AES256"),
  211 + new OctetString("v3group"),
  212 + StorageType.nonVolatile);
  213 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  214 + new OctetString("aboba"),
  215 + new OctetString("v3group"),
  216 + StorageType.nonVolatile);
  217 + //============================================//
  218 + // agent5-auth-priv
  219 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  220 + new OctetString("agent5"),
  221 + new OctetString("v3group"),
  222 + StorageType.nonVolatile);
  223 + //===========================================//
  224 + // agent002
  225 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  226 + new OctetString("agent002"),
  227 + new OctetString("v3group"),
  228 + StorageType.nonVolatile);
  229 + //===========================================//
  230 + // user001-auth-no-priv
  231 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  232 + new OctetString("user001"),
  233 + new OctetString("group001"),
  234 + StorageType.nonVolatile);
  235 + //===========================================//
  236 +
  237 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  238 + new OctetString("v3notify"),
  239 + new OctetString("v3group"),
  240 + StorageType.nonVolatile);
  241 +
  242 + //===========================================//
  243 + // group auth no priv
  244 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  245 + new OctetString("v3notify-auth"),
  246 + new OctetString("group001"),
  247 + StorageType.nonVolatile);
  248 + //===========================================//
  249 +
  250 +
  251 +
  252 + // my conf
  253 + vacm.addAccess(new OctetString("group001"), new OctetString("public"),
  254 + SecurityModel.SECURITY_MODEL_USM,
  255 + SecurityLevel.AUTH_NOPRIV,
  256 + MutableVACM.VACM_MATCH_EXACT,
  257 + new OctetString("fullReadView"),
  258 + new OctetString("fullWriteView"),
  259 + new OctetString("fullNotifyView"),
  260 + StorageType.nonVolatile);
  261 +
  262 + vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"),
  263 + SecurityModel.SECURITY_MODEL_ANY,
  264 + SecurityLevel.NOAUTH_NOPRIV,
  265 + MutableVACM.VACM_MATCH_EXACT,
  266 + new OctetString("fullReadView"),
  267 + new OctetString("fullWriteView"),
  268 + new OctetString("fullNotifyView"),
  269 + StorageType.nonVolatile);
  270 + vacm.addAccess(new OctetString("v3group"), new OctetString(),
  271 + SecurityModel.SECURITY_MODEL_USM,
  272 + SecurityLevel.AUTH_PRIV,
  273 + MutableVACM.VACM_MATCH_EXACT,
  274 + new OctetString("fullReadView"),
  275 + new OctetString("fullWriteView"),
  276 + new OctetString("fullNotifyView"),
  277 + StorageType.nonVolatile);
  278 + vacm.addAccess(new OctetString("v3restricted"), new OctetString(),
  279 + SecurityModel.SECURITY_MODEL_USM,
  280 + SecurityLevel.NOAUTH_NOPRIV,
  281 + MutableVACM.VACM_MATCH_EXACT,
  282 + new OctetString("restrictedReadView"),
  283 + new OctetString("restrictedWriteView"),
  284 + new OctetString("restrictedNotifyView"),
  285 + StorageType.nonVolatile);
  286 + vacm.addAccess(new OctetString("v3test"), new OctetString(),
  287 + SecurityModel.SECURITY_MODEL_USM,
  288 + SecurityLevel.AUTH_PRIV,
  289 + MutableVACM.VACM_MATCH_EXACT,
  290 + new OctetString("testReadView"),
  291 + new OctetString("testWriteView"),
  292 + new OctetString("testNotifyView"),
  293 + StorageType.nonVolatile);
  294 +
  295 + vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
  296 + new OctetString(), VacmMIB.vacmViewIncluded,
  297 + StorageType.nonVolatile);
  298 + vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
  299 + new OctetString(), VacmMIB.vacmViewIncluded,
  300 + StorageType.nonVolatile);
  301 + vacm.addViewTreeFamily(new OctetString("fullNotifyView"), new OID("1.3"),
  302 + new OctetString(), VacmMIB.vacmViewIncluded,
  303 + StorageType.nonVolatile);
  304 +
  305 + vacm.addViewTreeFamily(new OctetString("restrictedReadView"),
  306 + new OID("1.3.6.1.2"),
  307 + new OctetString(), VacmMIB.vacmViewIncluded,
  308 + StorageType.nonVolatile);
  309 + vacm.addViewTreeFamily(new OctetString("restrictedWriteView"),
  310 + new OID("1.3.6.1.2.1"),
  311 + new OctetString(),
  312 + VacmMIB.vacmViewIncluded,
  313 + StorageType.nonVolatile);
  314 + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
  315 + new OID("1.3.6.1.2"),
  316 + new OctetString(), VacmMIB.vacmViewIncluded,
  317 + StorageType.nonVolatile);
  318 + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
  319 + new OID("1.3.6.1.6.3.1"),
  320 + new OctetString(), VacmMIB.vacmViewIncluded,
  321 + StorageType.nonVolatile);
34 322
35   - USM usm = new USM();
36   - SecurityModels.getInstance().addSecurityModel(usm);
  323 + vacm.addViewTreeFamily(new OctetString("testReadView"),
  324 + new OID("1.3.6.1.2"),
  325 + new OctetString(), VacmMIB.vacmViewIncluded,
  326 + StorageType.nonVolatile);
  327 + vacm.addViewTreeFamily(new OctetString("testReadView"),
  328 + new OID("1.3.6.1.2.1.1"),
  329 + new OctetString(), VacmMIB.vacmViewExcluded,
  330 + StorageType.nonVolatile);
  331 + vacm.addViewTreeFamily(new OctetString("testWriteView"),
  332 + new OID("1.3.6.1.2.1"),
  333 + new OctetString(),
  334 + VacmMIB.vacmViewIncluded,
  335 + StorageType.nonVolatile);
  336 + vacm.addViewTreeFamily(new OctetString("testNotifyView"),
  337 + new OID("1.3.6.1.2"),
  338 + new OctetString(), VacmMIB.vacmViewIncluded,
  339 + StorageType.nonVolatile);
37 340
  341 + }
  342 +
  343 + protected void addUsmUser(USM usm) {
  344 + UsmUser user = new UsmUser(new OctetString("SHADES"),
  345 + AuthSHA.ID,
  346 + new OctetString("SHADESAuthPassword"),
  347 + PrivDES.ID,
  348 + new OctetString("SHADESPrivPassword"));
  349 +// usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  350 + usm.addUser(user.getSecurityName(), null, user);
  351 + user = new UsmUser(new OctetString("TEST"),
  352 + AuthSHA.ID,
  353 + new OctetString("maplesyrup"),
  354 + PrivDES.ID,
  355 + new OctetString("maplesyrup"));
  356 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  357 + user = new UsmUser(new OctetString("SHA"),
  358 + AuthSHA.ID,
  359 + new OctetString("SHAAuthPassword"),
  360 + null,
  361 + null);
  362 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  363 + user = new UsmUser(new OctetString("SHADES"),
  364 + AuthSHA.ID,
  365 + new OctetString("SHADESAuthPassword"),
  366 + PrivDES.ID,
  367 + new OctetString("SHADESPrivPassword"));
  368 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  369 + user = new UsmUser(new OctetString("MD5DES"),
  370 + AuthMD5.ID,
  371 + new OctetString("MD5DESAuthPassword"),
  372 + PrivDES.ID,
  373 + new OctetString("MD5DESPrivPassword"));
  374 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  375 + user = new UsmUser(new OctetString("SHAAES128"),
  376 + AuthSHA.ID,
  377 + new OctetString("SHAAES128AuthPassword"),
  378 + PrivAES128.ID,
  379 + new OctetString("SHAAES128PrivPassword"));
  380 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  381 + user = new UsmUser(new OctetString("SHAAES192"),
  382 + AuthSHA.ID,
  383 + new OctetString("SHAAES192AuthPassword"),
  384 + PrivAES192.ID,
  385 + new OctetString("SHAAES192PrivPassword"));
  386 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  387 + user = new UsmUser(new OctetString("SHAAES256"),
  388 + AuthSHA.ID,
  389 + new OctetString("SHAAES256AuthPassword"),
  390 + PrivAES256.ID,
  391 + new OctetString("SHAAES256PrivPassword"));
  392 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  393 +
  394 + user = new UsmUser(new OctetString("MD5AES128"),
  395 + AuthMD5.ID,
  396 + new OctetString("MD5AES128AuthPassword"),
  397 + PrivAES128.ID,
  398 + new OctetString("MD5AES128PrivPassword"));
  399 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  400 + user = new UsmUser(new OctetString("MD5AES192"),
  401 + AuthHMAC192SHA256.ID,
  402 + new OctetString("MD5AES192AuthPassword"),
  403 + PrivAES192.ID,
  404 + new OctetString("MD5AES192PrivPassword"));
  405 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  406 + //==============================================================
  407 + user = new UsmUser(new OctetString("MD5AES256"),
  408 + AuthMD5.ID,
  409 + new OctetString("MD5AES256AuthPassword"),
  410 + PrivAES256.ID,
  411 + new OctetString("MD5AES256PrivPassword"));
  412 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  413 + user = new UsmUser(new OctetString("MD5AES256"),
  414 + AuthMD5.ID,
  415 + new OctetString("MD5AES256AuthPassword"),
  416 + PrivAES256.ID,
  417 + new OctetString("MD5AES256PrivPassword"));
  418 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  419 +
  420 + OctetString securityName = new OctetString("aboba");
  421 + OctetString authenticationPassphrase = new OctetString("abobaaboba");
  422 + OctetString privacyPassphrase = new OctetString("abobaaboba");
38 423 OID authenticationProtocol = AuthSHA.ID;
39   - OID privacyProtocol = PrivDES.ID;
  424 + OID privacyProtocol = PrivDES.ID; // FIXME: to config
  425 + user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase);
  426 + usm.addUser(user);
  427 +
  428 + //===============================================================//
  429 + user = new UsmUser(new OctetString("agent5"),
  430 + AuthSHA.ID,
  431 + new OctetString("authpass"),
  432 + PrivDES.ID,
  433 + new OctetString("privpass"));
  434 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  435 + //===============================================================//
  436 + // user001
  437 + user = new UsmUser(new OctetString("user001"),
  438 + AuthSHA.ID,
  439 + new OctetString("authpass"),
  440 + null, null);
  441 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  442 + //===============================================================//
  443 + // user002
  444 + user = new UsmUser(new OctetString("user001"),
  445 + null,
  446 + null,
  447 + null, null);
  448 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  449 + //===============================================================//
  450 +
  451 + user = new UsmUser(new OctetString("v3notify"),
  452 + null,
  453 + null,
  454 + null,
  455 + null);
  456 + usm.addUser(user.getSecurityName(), null, user);
  457 +
  458 + this.usm = usm;
  459 + }
  460 +
  461 + private static DefaultMOTable createStaticIfXTable() {
  462 + MOTableSubIndex[] subIndexes =
  463 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  464 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  465 + MOColumn[] columns = new MOColumn[19];
  466 + int c = 0;
  467 + columns[c++] =
  468 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  469 + MOAccessImpl.ACCESS_READ_ONLY); // ifName
  470 + columns[c++] =
  471 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  472 + MOAccessImpl.ACCESS_READ_ONLY); // ifInMulticastPkts
  473 + columns[c++] =
  474 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  475 + MOAccessImpl.ACCESS_READ_ONLY); // ifInBroadcastPkts
  476 + columns[c++] =
  477 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  478 + MOAccessImpl.ACCESS_READ_ONLY); // ifOutMulticastPkts
  479 + columns[c++] =
  480 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  481 + MOAccessImpl.ACCESS_READ_ONLY); // ifOutBroadcastPkts
  482 + columns[c++] =
  483 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  484 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInOctets
  485 + columns[c++] =
  486 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  487 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInUcastPkts
  488 + columns[c++] =
  489 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  490 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInMulticastPkts
  491 + columns[c++] =
  492 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  493 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInBroadcastPkts
  494 + columns[c++] =
  495 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  496 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutOctets
  497 + columns[c++] =
  498 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  499 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutUcastPkts
  500 + columns[c++] =
  501 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  502 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutMulticastPkts
  503 + columns[c++] =
  504 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  505 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutBroadcastPkts
  506 + columns[c++] =
  507 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  508 + MOAccessImpl.ACCESS_READ_WRITE); // ifLinkUpDownTrapEnable
  509 + columns[c++] =
  510 + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
  511 + MOAccessImpl.ACCESS_READ_ONLY); // ifHighSpeed
  512 + columns[c++] =
  513 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  514 + MOAccessImpl.ACCESS_READ_WRITE); // ifPromiscuousMode
  515 + columns[c++] =
  516 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  517 + MOAccessImpl.ACCESS_READ_ONLY); // ifConnectorPresent
  518 + columns[c++] =
  519 + new MOMutableColumn(c, SMIConstants.SYNTAX_OCTET_STRING, // ifAlias
  520 + MOAccessImpl.ACCESS_READ_WRITE, null);
  521 + columns[c++] =
  522 + new MOColumn(c, SMIConstants.SYNTAX_TIMETICKS,
  523 + MOAccessImpl.ACCESS_READ_ONLY); // ifCounterDiscontinuityTime
  524 +
  525 + DefaultMOTable ifXTable =
  526 + new DefaultMOTable(new OID("1.3.6.1.2.1.31.1.1.1"), indexDef, columns);
  527 + MOMutableTableModel model = (MOMutableTableModel) ifXTable.getModel();
  528 + Variable[] rowValues1 = new Variable[] {
  529 + new OctetString("Ethernet-0"),
  530 + new Integer32(1),
  531 + new Integer32(2),
  532 + new Integer32(3),
  533 + new Integer32(4),
  534 + new Integer32(5),
  535 + new Integer32(6),
  536 + new Integer32(7),
  537 + new Integer32(8),
  538 + new Integer32(9),
  539 + new Integer32(10),
  540 + new Integer32(11),
  541 + new Integer32(12),
  542 + new Integer32(13),
  543 + new Integer32(14),
  544 + new Integer32(15),
  545 + new Integer32(16),
  546 + new OctetString("My eth"),
  547 + new TimeTicks(1000)
  548 + };
  549 + Variable[] rowValues2 = new Variable[] {
  550 + new OctetString("Loopback"),
  551 + new Integer32(21),
  552 + new Integer32(22),
  553 + new Integer32(23),
  554 + new Integer32(24),
  555 + new Integer32(25),
  556 + new Integer32(26),
  557 + new Integer32(27),
  558 + new Integer32(28),
  559 + new Integer32(29),
  560 + new Integer32(30),
  561 + new Integer32(31),
  562 + new Integer32(32),
  563 + new Integer32(33),
  564 + new Integer32(34),
  565 + new Integer32(35),
  566 + new Integer32(36),
  567 + new OctetString("My loop"),
  568 + new TimeTicks(2000)
  569 + };
  570 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  571 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  572 + ifXTable.setVolatile(true);
  573 + return ifXTable;
  574 + }
  575 +
  576 + private static DefaultMOTable createStaticIfTable() {
  577 + MOTableSubIndex[] subIndexes =
  578 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  579 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  580 + MOColumn[] columns = new MOColumn[8];
  581 + int c = 0;
  582 + columns[c++] =
  583 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  584 + MOAccessImpl.ACCESS_READ_ONLY); // ifIndex
  585 + columns[c++] =
  586 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  587 + MOAccessImpl.ACCESS_READ_ONLY); // ifDescr
  588 + columns[c++] =
  589 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  590 + MOAccessImpl.ACCESS_READ_ONLY); // ifType
  591 + columns[c++] =
  592 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  593 + MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
  594 + columns[c++] =
  595 + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
  596 + MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
  597 + columns[c++] =
  598 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  599 + MOAccessImpl.ACCESS_READ_ONLY); // ifPhysAddress
  600 + columns[c++] =
  601 + new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, // ifAdminStatus
  602 + MOAccessImpl.ACCESS_READ_WRITE, null);
  603 + columns[c++] =
  604 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  605 + MOAccessImpl.ACCESS_READ_ONLY); // ifOperStatus
40 606
41   - UsmUser user = new UsmUser(new OctetString(securityName), authenticationProtocol, new OctetString(authenticationPassphrase), privacyProtocol, new OctetString(privacyPassphrase));
  607 + DefaultMOTable ifTable =
  608 + new DefaultMOTable(new OID("1.3.6.1.2.1.2.2.1"), indexDef, columns);
  609 + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
  610 + Variable[] rowValues1 = new Variable[] {
  611 + new Integer32(1),
  612 + new OctetString("eth0"),
  613 + new Integer32(6),
  614 + new Integer32(1500),
  615 + new Gauge32(100000000),
  616 + new OctetString("00:00:00:00:01"),
  617 + new Integer32(1),
  618 + new Integer32(1)
  619 + };
  620 + Variable[] rowValues2 = new Variable[] {
  621 + new Integer32(2),
  622 + new OctetString("loopback"),
  623 + new Integer32(24),
  624 + new Integer32(1500),
  625 + new Gauge32(10000000),
  626 + new OctetString("00:00:00:00:02"),
  627 + new Integer32(1),
  628 + new Integer32(1)
  629 + };
  630 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  631 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  632 + ifTable.setVolatile(true);
  633 + return ifTable;
42 634 }
43 635
44   - public void initV3(UsmUser user, String securityName) {
45   -// snmp.getUSM().addUser(user);
  636 + private static DefaultMOTable createStaticSnmp4sTable() {
  637 + MOTableSubIndex[] subIndexes =
  638 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  639 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  640 + MOColumn[] columns = new MOColumn[8];
  641 + int c = 0;
  642 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_NULL, MOAccessImpl.ACCESS_READ_ONLY); // testNull
  643 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // testBoolean
  644 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifType
  645 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
  646 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
  647 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, MOAccessImpl.ACCESS_READ_ONLY); //ifPhysAddress
  648 + columns[c++] = new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_WRITE,
  649 + null);
  650 + // ifAdminStatus
  651 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY);
  652 + // ifOperStatus
  653 +
  654 + DefaultMOTable ifTable =
  655 + new DefaultMOTable(new OID("1.3.6.1.4.1.50000.1.1"), indexDef, columns);
  656 + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
  657 + Variable[] rowValues1 = new Variable[] {
  658 + new Integer32(1),
  659 + new OctetString("eth0"),
  660 + new Integer32(6),
  661 + new Integer32(1500),
  662 + new Gauge32(100000000),
  663 + new OctetString("00:00:00:00:01"),
  664 + new Integer32(1),
  665 + new Integer32(1)
  666 + };
  667 + Variable[] rowValues2 = new Variable[] {
  668 + new Integer32(2),
  669 + new OctetString("loopback"),
  670 + new Integer32(24),
  671 + new Integer32(1500),
  672 + new Gauge32(10000000),
  673 + new OctetString("00:00:00:00:02"),
  674 + new Integer32(1),
  675 + new Integer32(1)
  676 + };
  677 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  678 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  679 + ifTable.setVolatile(true);
  680 + return ifTable;
  681 + }
  682 +
  683 + protected void initTransportMappings() throws IOException {
  684 + transportMappings = new TransportMapping[2];
  685 + Address addr = GenericAddress.parse(address);
  686 + TransportMapping tm =
  687 + TransportMappings.getInstance().createTransportMapping(addr);
  688 + transportMappings[0] = tm;
  689 + transportMappings[1] = new DefaultTcpTransportMapping(new TcpAddress(address));
  690 + }
  691 +
  692 + public void start(String ip, String port) throws IOException {
  693 + address = ip + "/" + port;
  694 + //BasicConfigurator.configure();
  695 + init();
  696 + addShutdownHook();
  697 +// loadConfig(ImportModes.REPLACE_CREATE);
  698 + getServer().addContext(new OctetString("public"));
  699 + finishInit();
  700 + run();
  701 + sendColdStartNotification();
  702 + }
  703 +
  704 + protected void unregisterManagedObjects() {
  705 + // here we should unregister those objects previously registered...
  706 + }
  707 +
  708 + protected void addCommunities(SnmpCommunityMIB communityMIB) {
  709 + Variable[] com2sec = new Variable[] {
  710 + new OctetString("public"), // community name
  711 + new OctetString("cpublic"), // security name
  712 + getAgent().getContextEngineID(), // local engine ID
  713 + new OctetString("public"), // default context name
  714 + new OctetString(), // transport tag
  715 + new Integer32(StorageType.nonVolatile), // storage type
  716 + new Integer32(RowStatus.active) // row status
  717 + };
  718 + MOTableRow row =
  719 + communityMIB.getSnmpCommunityEntry().createRow(
  720 + new OctetString("public2public").toSubIndex(true), com2sec);
  721 + communityMIB.getSnmpCommunityEntry().addRow((SnmpCommunityMIB.SnmpCommunityEntryRow) row);
  722 +// snmpCommunityMIB.setSourceAddressFiltering(true);
  723 + }
  724 +
  725 + protected void registerSnmpMIBs() {
  726 + heartbeatMIB = new Snmp4jHeartbeatMib(super.getNotificationOriginator(),
  727 + new OctetString(),
  728 + super.snmpv2MIB.getSysUpTime());
  729 + agentppSimulationMIB = new AgentppSimulationMib();
  730 + super.registerSnmpMIBs();
  731 + }
46 732
47   - UserTarget userTarget = new UserTarget();
48   - userTarget.setSecurityName(new OctetString(securityName));
49   - userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
  733 + protected void initMessageDispatcher() {
  734 + this.dispatcher = new MessageDispatcherImpl();
  735 + this.mpv3 = new MPv3(this.agent.getContextEngineID().getValue());
  736 + this.usm = new USM(SecurityProtocols.getInstance(), this.agent.getContextEngineID(), this.updateEngineBoots());
  737 + SecurityModels.getInstance().addSecurityModel(this.usm);
  738 + SecurityProtocols.getInstance().addDefaultProtocols();
  739 + this.dispatcher.addMessageProcessingModel(new MPv1());
  740 + this.dispatcher.addMessageProcessingModel(new MPv2c());
  741 + this.dispatcher.addMessageProcessingModel(this.mpv3);
  742 + this.initSnmpSession();
50 743 }
51 744
52   -}
  745 +}
\ No newline at end of file
... ...
common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpTestV2.java renamed from common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpTest.java
... ... @@ -19,7 +19,7 @@ import java.io.IOException;
19 19 import java.util.Map;
20 20 import java.util.Scanner;
21 21
22   -public class SnmpTest {
  22 +public class SnmpTestV2 {
23 23 public static void main(String[] args) throws IOException {
24 24 SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public");
25 25
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.snmp;
  17 +
  18 +import org.snmp4j.CommandResponderEvent;
  19 +import org.snmp4j.agent.CommandProcessor;
  20 +import org.snmp4j.mp.MPv3;
  21 +import org.snmp4j.smi.OctetString;
  22 +
  23 +import java.io.IOException;
  24 +import java.util.Map;
  25 +import java.util.Scanner;
  26 +
  27 +public class SnmpTestV3 {
  28 + public static void main(String[] args) throws IOException {
  29 + SnmpDeviceSimulatorV3 device = new SnmpDeviceSimulatorV3(new CommandProcessor(new OctetString(MPv3.createLocalEngineID())) {
  30 + @Override
  31 + public void processPdu(CommandResponderEvent event) {
  32 + System.out.println("event: " + event);
  33 + }
  34 + });
  35 + device.start("0.0.0.0", "1610");
  36 +
  37 + device.setUpMappings(Map.of(
  38 + ".1.3.6.1.2.1.1.1.50", "12",
  39 + ".1.3.6.1.2.1.2.1.52", "56",
  40 + ".1.3.6.1.2.1.3.1.54", "yes",
  41 + ".1.3.6.1.2.1.7.1.58", ""
  42 + ));
  43 +
  44 + new Scanner(System.in).nextLine();
  45 + }
  46 +}
... ...
... ... @@ -38,16 +38,6 @@
38 38 "dataType": "STRING"
39 39 }
40 40 ]
41   - },
42   - {
43   - "spec": "TELEMETRY_TRAPS_RECEIVING",
44   - "mappings": [
45   - {
46   - "oid": ".1.3.6.1.2.8.7.1.56",
47   - "key": "temperature_trap",
48   - "dataType": "LONG"
49   - }
50   - ]
51 41 }
52 42 ]
53 43 }
... ...
  1 +{
  2 + "address": "192.168.3.23",
  3 + "port": 1610,
  4 + "protocolVersion": "V3",
  5 +
  6 + "username": "tb-user",
  7 + "engineId": "qwertyuioa",
  8 + "securityName": "tb-user",
  9 + "authenticationProtocol": "SHA_512",
  10 + "authenticationPassphrase": "sdfghjkloifgh",
  11 + "privacyProtocol": "DES",
  12 + "privacyPassphrase": "rtytguijokod"
  13 +}
\ No newline at end of file
... ...
1 1 {
2 2 "address": "127.0.0.1",
3 3 "port": 1610,
4   - "password": "public",
  4 + "community": "public",
5 5 "protocolVersion": "V2C"
6 6 }
\ No newline at end of file
... ...
... ... @@ -558,6 +558,14 @@ public class JsonConverter {
558 558 }
559 559 }
560 560
  561 + public static JsonElement parse(String json) {
  562 + return JSON_PARSER.parse(json);
  563 + }
  564 +
  565 + public static String toJson(JsonElement element) {
  566 + return GSON.toJson(element);
  567 + }
  568 +
561 569 public static void setTypeCastEnabled(boolean enabled) {
562 570 isTypeCastEnabled = enabled;
563 571 }
... ... @@ -599,8 +607,7 @@ public class JsonConverter {
599 607 .build();
600 608 }
601 609
602   - private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String
603   - provisionKey, String provisionSecret) {
  610 + private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String provisionKey, String provisionSecret) {
604 611 return TransportProtos.ProvisionDeviceCredentialsMsg.newBuilder()
605 612 .setProvisionDeviceKey(provisionKey)
606 613 .setProvisionDeviceSecret(provisionSecret)
... ...