SNMP/UDP trap handler
SNMP/UDP trap handler controller provides easy-to-use way to process SNMP v1/v2c and EVA ICS native UDP traps.
SNMP Traps
Processing
A trap data is parsed and processed later with a custom lmacro with the following keyword arguments:
Name |
Type |
Content |
---|---|---|
trap_source |
String |
SNMP trap sender IP address |
trap_community |
String |
SNMP trap community |
trap_vars |
Map<String, Any> |
Trap variables map as SNMP_OID=VAL |
Supported SNMP data types
The following SNMP data types are parsed and sent in trap_vars:
Type |
Processed as |
---|---|
BER (X.690) |
u64/i64/bool/String |
Counter32 |
u32 |
Gauge32 |
u32 |
UInteger32 |
u32 |
Counter64 |
u64 |
String |
String |
Unsupported data types are ignored.
Native traps
EVA ICS native traps is a native UDP signaling trap protocol, which replaces v3 UC UDP API.
The native trap structure is a string with new-line (LF) separated commands, e.g.:
u sensor:env/temp 1 25.57
a unit:tests/motor1 1 34.22
a unit:tests/relay1 toggle
Note
Native traps are processed by the service directly, the process macro is not required to be set.
Updates
Update commands have the following format:
u[pdate] <OID> <status> [value]
Example:
u sensor:env/temp 1 25.57
Actions
Action commands have the following format:
action <OID> exec <value>
# or in short
a <OID> x <value>
Example:
a unit:tests/motor1 x 34.22
If a toggle-action is required to be executed, use “t” (or “toggle”) with no value:
action unit:tests/fan toggle
Encrypted/compressed traps
The service supports encrypted and/or compressed trap payloads. The frame format is the same as for replication bulk events.
For encrypted frames, key_svc parameter in the service config is mandatory.
A Python example, which sends bzip2-compressed plus AES-256-GCM-encrypted native traps:
import socket
import bz2
from Cryptodome import Random
from Cryptodome.Cipher import AES
from hashlib import sha256
sender = ''
key_id = 'mykey'
key_val = 'SECRET'
payload = """
u sensor:env/temp 1 25.57
a unit:tests/door t
a unit:tests/u2 1
"""
flags = 2 + (1 << 4) # 2 = AES-256-GCM, 5th bit = 1 - bzip2
nonce = Random.new().read(12)
hasher = sha256()
hasher.update(key_val.encode())
cipher = AES.new(hasher.digest(), AES.MODE_GCM, nonce)
frame, digest = cipher.encrypt_and_digest(bz2.compress(payload.encode()))
binary_payload = b'\x00\x01' + flags.to_bytes(
1, 'little') + b'\x00\x00' + sender.encode() + b'\x00' + key_id.encode(
) + b'\x00' + frame + digest + nonce
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(binary_payload, ('127.0.0.1', 1162))
Setup
Use the template EVA_DIR/share/svc-tpl/svc-tpl-controller-trap.yml:
# SNMP trap handler controller
command: svc/eva-controller-trap
bus:
path: var/bus.ipc
config:
listen: 0.0.0.0:1162
# valid values
# snmp_v1 - SNMP v1
# snmp_v2c - SNMP v2c (default)
# eva_v1 - EVA ICS native UDP traps v1
protocol: snmp_v2c
# accepted communities
communities:
- public
# accepted hosts/networks
hosts_allow:
- 127.0.0.1
- 10.0.0.0/8
# process lmacro OID, required for SNMP traps
process: lmacro:tests/trap_handler
# key service, required for encrypted traps (native)
key_svc: eva.aaa.localauth
# allow encrypted traps only (native)
require_auth: false
# verbose info logging
verbose: false
mibs:
# if SNMP mibs are enabled, the process macro receives MIB-converted var
# names. MIB conversion uses net-snmp (built-in) library, which may be
# considered as unsafe. DO NOT USE MIBs FROM UNVERIFIED SOURCES.
#
# Usually requires installing base MIBs (libsnmp-base, snmp-mibs-downloader
# and/or related system packages)
enabled: false
#files:
#- /path/to/file.mib
dirs:
- /usr/share/snmp/mibs
- /usr/share/snmp/mibs/iana
- /usr/share/snmp/mibs/ietf
user: nobody
Create the service using eva-shell:
eva svc create eva.controller.trap1 /opt/eva4/share/svc-tpl/svc-tpl-controller-trap.yml
or using the bus CLI client:
cd /opt/eva4
cat DEPLOY.yml | ./bin/yml2mp | \
./sbin/bus ./var/bus.ipc rpc call eva.core svc.deploy -
(see eva.core::svc.deploy for more info)