1. Sammendrag
SNMP Trap Sender simulerer en nettverksenhet som sender SNMP-varsler. Den kan sende en periodisk heartbeat, simulere en omstart, ta et nettverksgrensesnitt ned og opp, og sende testmeldinger i fritekst eller salver for lasttesting. Varslene sendes som SNMPv1-traps, SNMPv2c-traps eller -informs, eller SNMPv3-traps eller -informs, til én eller flere trap-mottakere.
Simulatoren har sin egen MIB, TRAPSIM-MIB. Lastet opp til en
trap-mottaker gjør den at mottakeren viser hvert simulert varsel med navn.
Standardhendelsene bruker SNMPv2-MIB (coldStart, warmStart) og IF-MIB
(linkDown, linkUp), som alle mottakere allerede kjenner.
Den kjører som en systemd-tjeneste på Rocky Linux 9, enten i en VM eller i en Proxmox LXC-container. Den styres fra et web-GUI på engelsk eller norsk og installeres fra én fil uten tilgang til internett. Den er motstykket til SNMP Trap Receiver 2.0.
2. Formål og omfang
Simulerer |
Én nettverksenhet med navn, SNMPv1-agentadresse, SNMPv3-engine-ID, |
Sender |
SNMPv1 Trap-PDU, SNMPv2c Trap og InformRequest, SNMPv3 Trap og InformRequest (USM: noAuthNoPriv, authNoPriv, authPriv; MD5, SHA-1, SHA-2; DES, 3DES, AES-128/192/256) over UDP/IPv4 og UDP/IPv6 |
Hendelser |
Heartbeat, omstart (varslet, cold/warm start, enheten oppe), grensesnitt nede/oppe (IF-MIB og TRAPSIM-MIB) og testmelding |
Scenarier |
Omstart med nedetid, grensesnitt som blafrer (gjentatt nede/oppe) og salve med fast takt |
Planer |
En hvilken som helst hendelse gjentatt hvert N. sekund, for eksempel en heartbeat hvert 60. sekund |
Gjør ikke |
Svarer ikke på SNMP GET, er ikke en ekte agent og tar ikke imot traps |
3. Arkitektur
Rocky Linux 9 (VM eller Proxmox LXC)
┌───────────────────────────────────────────────────────────────┐
│ snmp-trap-sender.service (bruker trapsender) │
│ │
│ ┌──────────────┐ ┌────────────────────────────────────────┐ │
│ │ Flask-app på │ │ Motor: tråd + asyncio-hendelsesløkke │ │
│ │ Waitress ├─►│ send() planer scenarier │ │
│ │ (8 tråder) │ │ én pysnmp SnmpEngine per mottaker │ │
│ └──────▲───────┘ └──────────┬───────────────────┬─────────┘ │
│ │ │ │ │
│ state.json (enhet, │ historikk (2000) │ │
│ mottakere, planer) │ + sent_traps.jsonl│ │
└─────────┼─────────────────────┼───────────────────┼───────────┘
│ HTTP 8080 │ UDP → 162 │ UDP → 162
┌─────┴─────┐ ┌───────┴────────┐ ┌───────┴────────┐
│ nettleser │ │ trap-mottaker 1│ │ trap-mottaker 2│
└───────────┘ └────────────────┘ └────────────────┘
Alt kjører i én prosess. All SNMP-trafikk går i én asyncio-hendelsesløkke
i en egen tråd. Web-forespørsler gir arbeidet til den løkka med
run_coroutine_threadsafe og venter på svaret. Planer og scenarier er
asyncio-oppgaver i den samme løkka, så de blokkerer aldri GUI-et.
Motoren har én pysnmp SnmpEngine per mottaker. Når flere mottakere
deler én motor, sender det høynivå-API-et i pysnmp senere varsler også til
mottakerne fra tidligere kall. Egne motorer hindrer det, og de lar også en
v3-mottaker bruke enhetens egen engine-ID. En motor bygges på nytt når
mottakeren eller engine-ID-en endres.
3.1. Moduler
| Modul | Ansvar |
|---|---|
|
Hendelseskatalogen: OID per hendelse, parametere, validering, og hvordan hver hendelse blir til variabelbindinger |
|
|
|
Simulert enhet, mottakere og planer i |
|
|
|
Flask-GUI og JSON-API: innlogging, CSRF og sikkerhetshoder |
|
GUI-tekster på engelsk og norsk (196 nøkler; begge språkene må ha de samme nøklene) |
|
Viser brukermanualen ( |
|
Ende-til-ende-test med en midlertidig lokal mottaker |
|
Kommandolinje: |
|
Simulatorens MIB |
4. Hendelser
Hvert varsel starter med sysUpTime.0 (oppetiden til den simulerte
enheten) og snmpTrapOID.0. For SNMPv1-mottakere legges
snmpTrapAddress.0 til når en agentadresse er satt. pysnmp bruker den som
feltet agent-addr i Trap-PDU-en (RFC 3584), og gjør om varslets OID til
feltene enterprise, generic-trap og specific-trap i v1.
| Hendelse | Varsel | Variabler |
|---|---|---|
Heartbeat |
|
tsimDeviceName, tsimSequence (1, 2, 3 … siden forrige omstart), tsimInterval |
Omstart varslet |
|
tsimDeviceName, tsimRebootReason, tsimDowntime, tsimMessage |
Enheten oppe |
|
tsimDeviceName, tsimRebootReason, tsimDowntime |
Grensesnitt nede / oppe |
|
tsimDeviceName, tsimIfIndex, tsimIfName, tsimIfAlias, tsimSeverity, tsimMessage |
Testmelding |
|
tsimDeviceName, tsimSeverity, tsimMessage |
coldStart / warmStart |
|
– |
linkDown / linkUp |
|
ifIndex.n, ifAdminStatus.n = up(1), ifOperStatus.n = down(2) / up(1), pluss ifName.n og ifAlias.n, slik mange leverandører gjør |
Parameterne valideres på serveren: ifIndex 1…2147483647, nedetid 0…86400 sekunder, alvorlighet og årsak fra oppramsingene i MIB-en, grensesnittnavn og beskrivelse opptil 64 tegn og melding opptil 255.
5. TRAPSIM-MIB
MIB-en er SMIv2 og består smilint -l 6 (libsmis strengeste nivå) uten
merknader. Den ligger under enterprise 32473, som IANA har reservert for
dokumentasjon og eksempler (RFC 5612). Den kolliderer derfor aldri med
OID-ene til en ekte leverandør.
1.3.6.1.4.1.32473 example (RFC 5612)
└─ .1 trapSimRoot
└─ .1 trapSimMIB (MODULE-IDENTITY)
├─ .0 trapSimNotifications
│ ├─ .1 tsimHeartbeat .4 tsimInterfaceDown
│ ├─ .2 tsimReboot .5 tsimInterfaceUp
│ ├─ .3 tsimDeviceUp .6 tsimTestMessage
├─ .1 trapSimObjects (accessible-for-notify)
│ ├─ .1 tsimDeviceName .5 tsimRebootReason .9 tsimIfAlias
│ ├─ .2 tsimSequence .6 tsimDowntime .10 tsimMessage
│ ├─ .3 tsimInterval .7 tsimIfIndex
│ └─ .4 tsimSeverity .8 tsimIfName
└─ .2 trapSimConformance (krav og grupper)
Oppramsinger: TrapSimSeverity = clear(1), info(2), warning(3),
minor(4), major(5), critical(6); TrapSimRebootReason =
operatorRequest(1), softwareUpgrade(2), powerFailure(3), watchdog(4),
crash(5), scheduled(6).
Fila ligger i Documentation/MIB/, i Offline-Installation/ og i det
installerte programmet (/opt/snmp-trap-sender/app/trapsender/mib/). Den
kan også lastes ned fra fanen Enhet.
6. Scenarier
Omstart |
Sender |
Grensesnitt som blafrer |
Antall ganger: grensesnitt nede, vent nede sekunder, grensesnitt oppe, vent oppe sekunder. Varslene er |
Salve |
Antall varsler av én hendelse med takt per sekund. Takten følger en fast tidsplan, så én treg sending strekker ikke ut hele salven. Grenser: |
Scenarier sender til alle aktive mottakere, kjører i bakgrunnen, viser fremdriften i GUI-et og kan avbrytes. Avbrytes en omstart, avsluttes «nede»-tilstanden med en gang.
7. Planer
En plan gjentar én hendelse med faste parametere hvert intervall sekund
(1…86 400) til alle aktive mottakere eller til utvalgte mottakere. Første
sending skjer når planen startes. En ny installasjon har en Heartbeat-plan
som er slått av. Installeren kan slå den på med --heartbeat N. Planer
lagres i state.json og starter igjen sammen med tjenesten.
8. Mottakere
En mottaker er én trap-mottaker: vertsnavn eller IP-adresse (IPv4 eller IPv6), UDP-port, SNMP-versjon, trap eller inform, community (v1/v2c) eller USM-bruker med protokoller og nøkler (v3), tidsavbrudd og nye forsøk (brukes av informs), og en bryter for aktiv.
-
Traps sendes uten kvittering. Sendt betyr at pakken forlot senderen, ikke at en mottaker godtok den.
-
Informs kvitteres av mottakeren. Mangler kvitteringen etter tidsavbrudd og nye forsøk, vises det som feil. Informs er måten å sjekke at mottakeren faktisk fikk varselet.
-
SNMPv3-traps sendes med den simulerte enhetens engine-ID som autoritativ motor. Mottakeren må ha den samme brukeren for den engine-ID-en. GUI-et viser linja som skal inn i konfigurasjonen til SNMP Trap Receiver (
[v3user:NAVN]…engine_id = …).
Communities og v3-nøkler lagres i state.json (modus 0600, bare lesbar for
tjenestebrukeren). De sendes aldri tilbake til nettleseren.
Redigeringsskjemaet viser «uendret» og beholder den lagrede verdien når
feltet står tomt.
9. Simulert enhet
Navn |
Sendes som |
Agentadresse |
Valgfri IPv4-adresse som legges i SNMPv1-traps som |
sysUpTime |
Teller fra forrige (simulerte) omstart i hundredels sekunder og starter på nytt ved 232 |
Heartbeat-nummer |
+1 per heartbeat (samme nummer til alle mottakere), tilbake til 0 ved en omstart. En mottaker kan se tapte heartbeats av hull i rekka. |
Engine-ID |
Format etter RFC 3411: |
10. Web-GUI og API
10.1. Sider
Send |
Hurtigknapper (Heartbeat, Omstart, Grensesnitt nede, Grensesnitt oppe), et skjema for en hvilken som helst hendelse med parametere og valgte mottakere, scenarier, og pågående eller siste scenarier med Avbryt |
Planer |
Tabell med av/på-bryter per plan; opprett, endre og slett |
Mottakere |
Tabell; opprett, endre, slett og Test (sender en testmelding til den mottakeren og viser resultatet) |
Historikk |
De siste 2000 varslene med tid, varsel, mottaker, versjon, kilde (manuell, plan, scenario, CLI) og resultat; filter; nedlasting av loggen |
Enhet |
Simulert enhet, oppetid, heartbeat-nummer, omstarter, engine-ID og tellere; nedlasting av TRAPSIM-MIB |
Topplinje |
Enheten er oppe / Enheten starter på nytt (n s), enhetsnavn og oppetid, EN/NO og Logg ut |
Bunnlinje |
Versjon, Lisenser, Lisensrapport og Third-party notices |
10.2. Endepunkter
| Sti | Metode | Formål |
|---|---|---|
|
Sesjon og språk |
|
|
GET |
|
|
GET |
Brukermanualen på valgt språk, med innholdsfortegnelse og søk. Brukermanual-knappen lenker til |
|
GET |
Hendelseskatalog, oppramsinger og grenser |
|
GET |
Enhet, oppetid, nede-tilstand, tellere og scenarier |
|
POST |
|
|
POST |
|
|
POST |
Avbryt |
|
GET/POST |
Liste (uten hemmeligheter) / opprett eller oppdater |
|
POST |
Test / slett |
|
GET/POST |
Planer |
|
POST |
På/av / slett |
|
GET |
Sendte varsler med |
|
POST |
Enhetsnavn og agentadresse / ny engine-ID |
|
GET |
TRAPSIM-MIB / |
|
GET |
Lisensdata |
10.3. Sikkerhet
Samme modell som SNMP Trap Receiver: ett passord (scrypt-hash),
sesjonskapsel med HttpOnly og SameSite=Strict, forsinkelse etter 5
feilede innlogginger, CSRF-token på hver POST,
Content-Security-Policy: default-src 'self' uten innebygd skript,
X-Frame-Options: DENY og nosniff. Alle verdier escapes før de vises,
og forespørsler er begrenset til 256 KB.
Senderen kan brukes til å oversvømme en mottaker (salve). Tilgangen til GUI-et bør derfor begrenses til dem som kjører tester.
11. Konfigurasjon
/etc/snmp-trap-sender/config.ini (root:trapsender, 0640). Start
tjenesten på nytt etter en endring.
| Seksjon | Nøkkel | Standard | Betydning |
|---|---|---|---|
|
|
|
Adressen til web-GUI-et |
|
|
Innlogging |
|
|
|
|
|
|
|
||
|
|
|
Øvre grense for salver, per sekund |
|
|
Største salve |
|
|
|
Varsler som holdes for fanen Historikk |
|
|
|
|
|
|
|
|
|
|
|
Loggrotasjon |
Mottakere, planer og enheten endres i GUI-et og lagres i state.json.
12. Loggformat
Hver linje i sent_traps.jsonl er ett sendt varsel:
{"id": 42, "time": "2026-10-02 12:20:53", "ts": 1790936453.2,
"event": "sim_if_down", "trap": "TRAPSIM-MIB::tsimInterfaceDown",
"origin": "manual", "target": "Receiver", "target_id": "1cce00181e",
"dest": "172.16.101.83:162", "version": "v2c", "notify": "trap",
"params": {"if_index": 1, "if_name": "GigabitEthernet0/1",
"if_alias": "Uplink", "severity": "major",
"message": "Fibre cut on uplink"},
"result": "sent", "error": "", "ms": 1.4}
result er sent, acknowledged (inform besvart) eller error.
13. Installasjon og drift
13.1. Filer
Sti |
Eier, modus |
Innhold |
|
root |
Program, Python-miljø og dokumentasjon; |
|
root:trapsender, 0640 |
Konfigurasjon |
|
trapsender, 0600 |
Enhet, mottakere (med hemmeligheter) og planer |
|
trapsender, 0750 |
|
|
root, 0755 |
Kommandolinje |
13.2. systemd og LXC
Tjenesten kjører som systembrukeren trapsender uten kapabiliteter.
Sending til port 162 krever ingen rettigheter, fordi kildeporten er en
tilfeldig høy port. Selve enheten setter bare NoNewPrivileges, et tomt
CapabilityBoundingSet og UMask=0027, og det virker i alle containere.
Mer sandkasse ligger i en drop-in-fil,
snmp-trap-sender.service.d/hardening.conf (ProtectSystem=strict,
PrivateTmp, PrivateDevices, ProtectKernel*, RestrictNamespaces,
RestrictAddressFamilies, …). Den krever mount-navnerom. De virker i VM-er
og i Proxmox LXC-containere med nesting slått på, som er standard for nye
uprivilegerte containere. Uten nesting stopper systemd tjenesten med
status=226/NAMESPACE. Installeren oppdager dette, fjerner drop-in-fila,
starter på nytt og sier ifra. --no-hardening hopper over drop-in-fila fra
starten.
Tjenesten lytter ikke på noen SNMP-port, så bare web-porten må være åpen.
13.3. Kommandolinje
|
Kjør (brukes av systemd) |
|
Web-passord (root) |
|
Legg til en mottaker, og start tjenesten på nytt etterpå |
|
Send én hendelse nå, f.eks. |
|
Ende-til-ende-test (se Verifisering) |
|
13.4. Offline-installeren
Samme oppbygging som for SNMP Trap Receiver. Et bash-hode kontrollerer
SHA-256 til arkivet som ligger bakerst med python3, pakker det ut med det
trygge datafilteret i tarfile og starter install.sh. Det skriptet
kontrollerer operativsystem, Python 3.9, arkitektur, glibc 2.34 eller nyere
og sjekksummene til filene. Så bygger det et virtuelt miljø bare fra
wheel-filene som følger med (uten nett), og installerer program, bruker,
konfigurasjon og systemd-enhet. Eventuelt legger det til en mottaker og en
heartbeat. Til slutt starter det tjenesten, venter på /healthz og kjører
selvtesten. En oppgradering beholder konfigurasjon, state.json og logger,
og flytter forrige program til .previous/.
build-offline-installer.sh bygger installeren på en hvilken som helst
maskin med internett. Den laster ned wheel-filene i
Application/requirements.lock for CPython 3.9 på x86_64 og aarch64,
genererer lisensfilene og GPL-skanningen, kontrollerer en
offline-installasjon med Python 3.9 hvis byggemaskinen har det, og kjører
pip-audit hvis det er installert.
14. Verifisering
snmp-trap-sender selftest starter en pysnmp-mottaker på en ledig port på
127.0.0.1 (community selftest og én v3-bruker med SHA-256/AES-128 for
senderens engine-ID) og bruker midlertidige mapper. Den kontrollerer:
-
at
state.jsonhar modus 0600, at fire mottakere (v1, v2c trap, v2c inform, v3 authPriv) lagres, og at en ugyldig vert avvises; -
at hver av de 10 hendelsene kommer fram via alle fire mottakerne med riktig
snmpTrapOID, at versjonene v1, v2c og v3 kommer inn, at informs kvitteres, at agentadressen i v1 er den simulerte, at heartbeat har enhetsnavn og nummer 1, og atlinkDownhar ifIndex, ifAdminStatus = up og ifOperStatus = down; -
at omstartsscenariet gir
tsimReboot→coldStart→tsimDeviceUpog nullstillersysUpTime, heartbeat-nummer og omstartstelleren; at blafring ×2 med begge varseltyper gir 8 varsler; og at en salve på 40 med 100/s tar mellom 0,3 og 3 sekunder og leverer alle 40; -
at en heartbeat-plan hvert sekund gir stigende nummer, at historikk og logg skrives, og at en inform til en port uten mottaker gir feil;
-
web: innlogging, feil passord, engelsk som standard, CSRF, sending via API-et, avvisning av ugyldige parametere, ingen hemmeligheter i mottakerlista, at nøklene beholdes når en mottaker endres, start av scenario, nedlasting av MIB, brukermanualen på engelsk og norsk, norsk side, sikkerhetshoder, og lisensinventar og -dokumenter på begge språk.
Installeren kjører selvtesten etter hver installasjon (46 sjekker).
15. Begrensninger
-
Bare HTTP. Sett en omvendt proxy med TLS foran eller bruk SSH-tunnel over nett man ikke stoler på.
-
Én simulert enhet per installasjon. For flere enheter kjører du flere containere.
-
Simulatoren svarer ikke på SNMP GET, så en mottaker som poller enheten etter en trap, får ikke svar.
-
Målt på én kjerne: rundt 1000 v2c-traps i sekundet i en salve. pysnmp-motoren er begrensningen.
16. Lisenser
Alle tredjepartskomponentene har tillatende lisenser. Se
Lisensrapport.md, THIRD_PARTY_NOTICES.txt og
third_party_inventory.json. TRAPSIM-MIB er en del av dette prosjektet og
kan brukes, kopieres og endres fritt.
Vedlegg A: Porter
Port |
Protokoll |
Retning |
Formål |
8080 |
TCP |
inn |
Web-GUI (kan endres) |
162 (kan endres per mottaker) |
UDP |
ut |
Traps og informs til mottakerne |