Loading modules/snmp/snmp.cpp +29 −6 Changes for modules/snmp/snmp.cpp: 29 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -33,11 +33,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * settings: enabled, interval, events, report{raid, lvm, * filesystems, disks, smart_attributes, services}, fsWarning, * fsCritical, tempWarning, tempCritical, * services[], targets[{host, port, version, community}], * enterprise (read only) * services[], targets[{host, port, version, community (1, 2c); * user, level, auth, authPasswordSet, priv, privPasswordSet * (3)}], enterprise, engineId (read only) * status: lastReport, nextReport (unix time, 0: never/off), sent, * status, problems[], targets[{target, sent, error}] * save {settings} replaces them all (as above, without enterprise) * status, engineId, engineBoots, problems[], * targets[{target, sent, error}] * save {settings} replaces them all (as above, without enterprise and * engineId; version 3: authPassword, privPassword -- * empty keeps the target's current one) * send a report now -> {sent} */ Loading Loading @@ -90,13 +94,20 @@ json_object *settingsJson(const sysbus::Message &r) { else if (k.compare(0, 7, "report_") == 0) json_object_object_add(report, k.c_str() + 7, json_object_new_boolean(v == "yes")); else if (k == "enterprise") json_object_object_add(o, "enterprise", jstr(v)); else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v)); else if (k == "service") json_object_array_add(services, jstr(v)); else if (k == "target") { target = json_object_new_object(); json_object_array_add(targets, target); json_object_object_add(target, "host", jstr(v)); } else if (target && k == "port") json_object_object_add(target, "port", json_object_new_int64(num(v))); else if (target && (k == "version" || k == "community")) json_object_object_add(target, k.c_str(), jstr(v)); else if (target && (k == "version" || k == "community" || k == "user" || k == "level" || k == "auth" || k == "priv")) json_object_object_add(target, k.c_str(), jstr(v)); else if (target && k == "auth_password_set") json_object_object_add(target, "authPasswordSet", json_object_new_boolean(v == "yes")); else if (target && k == "priv_password_set") json_object_object_add(target, "privPasswordSet", json_object_new_boolean(v == "yes")); } json_object_object_add(o, "report", report); json_object_object_add(o, "services", services); Loading @@ -120,6 +131,8 @@ json_object *statusJson(const sysbus::Message &r) { else if (k == "next_report") json_object_object_add(o, "nextReport", json_object_new_int64(num(v))); else if (k == "sent") json_object_object_add(o, "sent", json_object_new_int64(num(v))); else if (k == "status") json_object_object_add(o, "status", jstr(v)); else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v)); else if (k == "engine_boots") json_object_object_add(o, "engineBoots", json_object_new_int64(num(v))); else if (k == "problem") json_object_array_add(problems, jstr(v)); } json_object_object_add(o, "problems", problems); Loading Loading @@ -158,8 +171,18 @@ std::string settingsFields(json_object *s, Fields &out) { if (!t || !json_object_is_type(t, json_type_object)) return tr("invalid target", "ungültiges Ziel"); out.emplace_back("target", webctl::str(t, "host")); out.emplace_back("port", std::to_string(webctl::integer(t, "port", 162))); out.emplace_back("version", webctl::str(t, "version", "2c")); std::string version = webctl::str(t, "version", "2c"); out.emplace_back("version", version); if (version != "3") { out.emplace_back("community", webctl::str(t, "community")); continue; } out.emplace_back("user", webctl::str(t, "user")); out.emplace_back("level", webctl::str(t, "level", "authPriv")); out.emplace_back("auth", webctl::str(t, "auth", "SHA-256")); out.emplace_back("auth_password", webctl::str(t, "authPassword")); out.emplace_back("priv", webctl::str(t, "priv", "AES")); out.emplace_back("priv_password", webctl::str(t, "privPassword")); } } return ""; Loading www/modules/snmp.js +80 −10 Changes for www/modules/snmp.js: 80 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,19 @@ 'ok': 'ok', 'warning': 'Warnung', 'critical': 'kritisch', 'unknown': 'unbekannt', 'Targets (NMS)': 'Ziele (NMS)', 'Add target': 'Ziel hinzufügen', 'Host': 'Host', 'Port': 'Port', 'Version': 'Version', 'Community': 'Community', 'Sent': 'Gesendet', 'Error': 'Fehler', 'Security': 'Sicherheit', 'clear text': 'Klartext', 'unchanged': 'unverändert', 'at least 8 characters': 'mindestens 8 Zeichen', 'User': 'Benutzer', 'Security level': 'Sicherheitsstufe', 'Authentication and encryption': 'Authentifizierung und Verschlüsselung', 'Authentication only': 'Nur Authentifizierung', 'Neither (not recommended)': 'Keine (nicht empfohlen)', 'Authentication': 'Authentifizierung', 'Authentication password': 'Authentifizierungs-Passwort', 'Encryption': 'Verschlüsselung', 'Encryption password': 'Verschlüsselungs-Passwort', 'AES-256 needs SHA-256 or SHA-384.': 'AES-256 braucht SHA-256 oder SHA-384.', 'SNMPv1 and v2c send the community and everything else in clear text.': 'SNMPv1 und v2c senden die Community und alles andere im Klartext.', 'SNMPv3 engine ID': 'SNMPv3-Engine-ID', '(boots {0})': '(Starts {0})', 'SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:': 'SNMPv3: Das NMS kennt jeden Benutzer unter der Engine-ID von snmpdd, z. B. in snmptrapd.conf:', 'user': 'Benutzer', 'password': 'Passwort', 'Edit': 'Bearbeiten', 'Remove': 'Entfernen', 'No targets yet.': 'Noch keine Ziele.', 'Target {0}': 'Ziel {0}', 'New target': 'Neues Ziel', 'Add': 'Hinzufügen', 'Host name or IP address of the network management station.': 'Hostname oder IP-Adresse der Network-Management-Station.', Loading Loading @@ -55,6 +68,7 @@ async function save(changes, success) { const s = {...data.settings, ...changes}; delete s.enterprise; delete s.engineId; await call('snmp', 'save', {settings: s}); toast(success); load(); Loading Loading @@ -110,22 +124,62 @@ function targetDialog(index) { const old = index >= 0 ? data.settings.targets[index] : null; const tg = old || {host: '', port: 162, version: '2c', community: 'public'}; const tg = {host: '', port: 162, version: '3', community: 'public', user: '', level: 'authPriv', auth: 'SHA-256', priv: 'AES', ...(old || {})}; const select = (name, values, value, labels) => h('select', {name}, values.map((v, i) => h('option', {value: v, selected: v === value}, labels ? labels[i] : v))); // a password that is set stays unless something is typed in const password = (name, isSet) => h('input', {name, type: 'password', autocomplete: 'new-password', maxlength: 255, placeholder: isSet ? t('unchanged') : t('at least 8 characters')}); dialog({ title: old ? t('Target {0}', old.host) : t('New target'), submit: old ? undefined : t('Add'), fields: () => [ fields: () => { const community = h('div', {}, h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, maxlength: 255})), h('p', {class: 'hint'}, t('SNMPv1 and v2c send the community and everything else in clear text.'))); const authBox = h('div', {class: 'row'}, h('label', {}, t('Authentication'), select('auth', ['SHA', 'SHA-256', 'SHA-384'], tg.auth, ['SHA-1', 'SHA-256', 'SHA-384'])), h('label', {}, t('Authentication password'), password('authPassword', old && old.authPasswordSet))); const privBox = h('div', {class: 'row'}, h('label', {}, t('Encryption'), select('priv', ['AES', 'AES-256'], tg.priv, ['AES-128', 'AES-256'])), h('label', {}, t('Encryption password'), password('privPassword', old && old.privPasswordSet))); const level = select('level', ['authPriv', 'authNoPriv', 'noAuthNoPriv'], tg.level, [t('Authentication and encryption'), t('Authentication only'), t('Neither (not recommended)')]); const v3 = h('div', {}, h('div', {class: 'row'}, h('label', {}, t('User'), h('input', {name: 'user', value: tg.user, maxlength: 32})), h('label', {}, t('Security level'), level)), authBox, privBox, h('p', {class: 'hint'}, t('AES-256 needs SHA-256 or SHA-384.'))); const version = select('version', ['3', '2c', '1'], tg.version, ['SNMPv3', 'SNMPv2c', 'SNMPv1']); const update = () => { const is3 = version.value === '3'; community.hidden = is3; v3.hidden = !is3; authBox.hidden = level.value === 'noAuthNoPriv'; privBox.hidden = level.value !== 'authPriv'; }; version.addEventListener('change', update); level.addEventListener('change', update); update(); return [ h('div', {class: 'row'}, h('label', {}, t('Host'), h('input', {name: 'host', value: tg.host, required: true})), h('label', {}, t('Port'), h('input', {name: 'port', type: 'number', min: 1, max: 65535, value: tg.port, required: true}))), h('p', {class: 'hint'}, t('Host name or IP address of the network management station.')), h('div', {class: 'row'}, h('label', {}, t('Version'), h('select', {name: 'version'}, ['2c', '1'].map(v => h('option', {value: v, selected: v === tg.version}, 'SNMPv' + v)))), h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, required: true, maxlength: 255}))), ], h('label', {}, t('Version'), version), community, v3, ]; }, onSubmit: d => { const targets = [...data.settings.targets]; const n = {host: d.host.trim(), port: Number(d.port), version: d.version, community: d.community}; const n = {host: d.host.trim(), port: Number(d.port), version: d.version}; if (d.version === '3') Object.assign(n, {user: d.user.trim(), level: d.level, auth: d.auth, priv: d.priv, authPassword: d.authPassword, privPassword: d.privPassword}); else n.community = d.community; if (old) targets[index] = n; else targets.push(n); return save({targets}, t('Target saved.')); Loading @@ -149,6 +203,17 @@ load(); } const levelText = {authPriv: 'authPriv', authNoPriv: 'authNoPriv', noAuthNoPriv: 'noAuthNoPriv'}; function security(tg) { if (tg.version !== '3') return [h('span', {class: 'badge warn'}, t('clear text')), ' ', h('span', {class: 'mono'}, tg.community)]; const strong = tg.level === 'authPriv'; return [h('span', {class: 'badge ' + (strong ? 'ok' : 'warn')}, levelText[tg.level] || tg.level), ' ', h('span', {class: 'mono'}, tg.user), tg.level !== 'noAuthNoPriv' ? h('span', {class: 'muted'}, ' ' + [tg.auth, strong ? tg.priv : null].filter(Boolean).join(' / ')) : null]; } function draw() { const s = data.settings, st = data.status; const row = (label, value) => h('tr', {}, h('th', {}, label), h('td', {}, value)); Loading @@ -170,7 +235,9 @@ row(t('Status'), st.lastReport ? badge(st.status) : '–'), st.problems.length ? row(t('Not collected'), st.problems.join('; ')) : null, row(t('Notifications sent'), String(st.sent || 0)), row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')))))), row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')), row(t('SNMPv3 engine ID'), [h('span', {class: 'mono'}, '0x' + (s.engineId || '')), st.engineBoots ? h('span', {class: 'muted'}, ' ' + t('(boots {0})', st.engineBoots)) : null]))))), h('section', {class: 'panel'}, h('div', {class: 'toolbar'}, h('h2', {}, t('Targets (NMS)')), Loading @@ -179,7 +246,7 @@ {title: t('Host'), render: tg => h('strong', {}, tg.host)}, {title: t('Port'), render: tg => tg.port, class: 'mono'}, {title: t('Version'), render: tg => 'SNMPv' + tg.version}, {title: t('Community'), render: tg => h('span', {class: 'mono'}, tg.community)}, {title: t('Security'), render: security}, {title: t('Sent'), render: tg => String((st.targets.find(x => x.target === key(tg)) || {}).sent || 0)}, {title: t('Error'), render: tg => { const e = (st.targets.find(x => x.target === key(tg)) || {}).error; Loading @@ -191,6 +258,9 @@ h('button', {class: 'small danger', onclick: () => removeTarget(i)}, t('Remove'))]; }}, ], s.targets, t('No targets yet.')), h('p', {class: 'hint'}, t('SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:')), h('pre', {class: 'log'}, 'createUser -e 0x' + (s.engineId || '…') + ' <' + t('user') + '> SHA-256 <' + t('password') + '> AES <' + t('password') + '>'), h('p', {class: 'hint'}, t('SNMPDD-MIB describes the notifications (/usr/share/snmp/mibs/SNMPDD-MIB.txt); load it into the NMS.')))); } Loading Loading
modules/snmp/snmp.cpp +29 −6 Changes for modules/snmp/snmp.cpp: 29 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -33,11 +33,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * settings: enabled, interval, events, report{raid, lvm, * filesystems, disks, smart_attributes, services}, fsWarning, * fsCritical, tempWarning, tempCritical, * services[], targets[{host, port, version, community}], * enterprise (read only) * services[], targets[{host, port, version, community (1, 2c); * user, level, auth, authPasswordSet, priv, privPasswordSet * (3)}], enterprise, engineId (read only) * status: lastReport, nextReport (unix time, 0: never/off), sent, * status, problems[], targets[{target, sent, error}] * save {settings} replaces them all (as above, without enterprise) * status, engineId, engineBoots, problems[], * targets[{target, sent, error}] * save {settings} replaces them all (as above, without enterprise and * engineId; version 3: authPassword, privPassword -- * empty keeps the target's current one) * send a report now -> {sent} */ Loading Loading @@ -90,13 +94,20 @@ json_object *settingsJson(const sysbus::Message &r) { else if (k.compare(0, 7, "report_") == 0) json_object_object_add(report, k.c_str() + 7, json_object_new_boolean(v == "yes")); else if (k == "enterprise") json_object_object_add(o, "enterprise", jstr(v)); else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v)); else if (k == "service") json_object_array_add(services, jstr(v)); else if (k == "target") { target = json_object_new_object(); json_object_array_add(targets, target); json_object_object_add(target, "host", jstr(v)); } else if (target && k == "port") json_object_object_add(target, "port", json_object_new_int64(num(v))); else if (target && (k == "version" || k == "community")) json_object_object_add(target, k.c_str(), jstr(v)); else if (target && (k == "version" || k == "community" || k == "user" || k == "level" || k == "auth" || k == "priv")) json_object_object_add(target, k.c_str(), jstr(v)); else if (target && k == "auth_password_set") json_object_object_add(target, "authPasswordSet", json_object_new_boolean(v == "yes")); else if (target && k == "priv_password_set") json_object_object_add(target, "privPasswordSet", json_object_new_boolean(v == "yes")); } json_object_object_add(o, "report", report); json_object_object_add(o, "services", services); Loading @@ -120,6 +131,8 @@ json_object *statusJson(const sysbus::Message &r) { else if (k == "next_report") json_object_object_add(o, "nextReport", json_object_new_int64(num(v))); else if (k == "sent") json_object_object_add(o, "sent", json_object_new_int64(num(v))); else if (k == "status") json_object_object_add(o, "status", jstr(v)); else if (k == "engine_id") json_object_object_add(o, "engineId", jstr(v)); else if (k == "engine_boots") json_object_object_add(o, "engineBoots", json_object_new_int64(num(v))); else if (k == "problem") json_object_array_add(problems, jstr(v)); } json_object_object_add(o, "problems", problems); Loading Loading @@ -158,8 +171,18 @@ std::string settingsFields(json_object *s, Fields &out) { if (!t || !json_object_is_type(t, json_type_object)) return tr("invalid target", "ungültiges Ziel"); out.emplace_back("target", webctl::str(t, "host")); out.emplace_back("port", std::to_string(webctl::integer(t, "port", 162))); out.emplace_back("version", webctl::str(t, "version", "2c")); std::string version = webctl::str(t, "version", "2c"); out.emplace_back("version", version); if (version != "3") { out.emplace_back("community", webctl::str(t, "community")); continue; } out.emplace_back("user", webctl::str(t, "user")); out.emplace_back("level", webctl::str(t, "level", "authPriv")); out.emplace_back("auth", webctl::str(t, "auth", "SHA-256")); out.emplace_back("auth_password", webctl::str(t, "authPassword")); out.emplace_back("priv", webctl::str(t, "priv", "AES")); out.emplace_back("priv_password", webctl::str(t, "privPassword")); } } return ""; Loading
www/modules/snmp.js +80 −10 Changes for www/modules/snmp.js: 80 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,19 @@ 'ok': 'ok', 'warning': 'Warnung', 'critical': 'kritisch', 'unknown': 'unbekannt', 'Targets (NMS)': 'Ziele (NMS)', 'Add target': 'Ziel hinzufügen', 'Host': 'Host', 'Port': 'Port', 'Version': 'Version', 'Community': 'Community', 'Sent': 'Gesendet', 'Error': 'Fehler', 'Security': 'Sicherheit', 'clear text': 'Klartext', 'unchanged': 'unverändert', 'at least 8 characters': 'mindestens 8 Zeichen', 'User': 'Benutzer', 'Security level': 'Sicherheitsstufe', 'Authentication and encryption': 'Authentifizierung und Verschlüsselung', 'Authentication only': 'Nur Authentifizierung', 'Neither (not recommended)': 'Keine (nicht empfohlen)', 'Authentication': 'Authentifizierung', 'Authentication password': 'Authentifizierungs-Passwort', 'Encryption': 'Verschlüsselung', 'Encryption password': 'Verschlüsselungs-Passwort', 'AES-256 needs SHA-256 or SHA-384.': 'AES-256 braucht SHA-256 oder SHA-384.', 'SNMPv1 and v2c send the community and everything else in clear text.': 'SNMPv1 und v2c senden die Community und alles andere im Klartext.', 'SNMPv3 engine ID': 'SNMPv3-Engine-ID', '(boots {0})': '(Starts {0})', 'SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:': 'SNMPv3: Das NMS kennt jeden Benutzer unter der Engine-ID von snmpdd, z. B. in snmptrapd.conf:', 'user': 'Benutzer', 'password': 'Passwort', 'Edit': 'Bearbeiten', 'Remove': 'Entfernen', 'No targets yet.': 'Noch keine Ziele.', 'Target {0}': 'Ziel {0}', 'New target': 'Neues Ziel', 'Add': 'Hinzufügen', 'Host name or IP address of the network management station.': 'Hostname oder IP-Adresse der Network-Management-Station.', Loading Loading @@ -55,6 +68,7 @@ async function save(changes, success) { const s = {...data.settings, ...changes}; delete s.enterprise; delete s.engineId; await call('snmp', 'save', {settings: s}); toast(success); load(); Loading Loading @@ -110,22 +124,62 @@ function targetDialog(index) { const old = index >= 0 ? data.settings.targets[index] : null; const tg = old || {host: '', port: 162, version: '2c', community: 'public'}; const tg = {host: '', port: 162, version: '3', community: 'public', user: '', level: 'authPriv', auth: 'SHA-256', priv: 'AES', ...(old || {})}; const select = (name, values, value, labels) => h('select', {name}, values.map((v, i) => h('option', {value: v, selected: v === value}, labels ? labels[i] : v))); // a password that is set stays unless something is typed in const password = (name, isSet) => h('input', {name, type: 'password', autocomplete: 'new-password', maxlength: 255, placeholder: isSet ? t('unchanged') : t('at least 8 characters')}); dialog({ title: old ? t('Target {0}', old.host) : t('New target'), submit: old ? undefined : t('Add'), fields: () => [ fields: () => { const community = h('div', {}, h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, maxlength: 255})), h('p', {class: 'hint'}, t('SNMPv1 and v2c send the community and everything else in clear text.'))); const authBox = h('div', {class: 'row'}, h('label', {}, t('Authentication'), select('auth', ['SHA', 'SHA-256', 'SHA-384'], tg.auth, ['SHA-1', 'SHA-256', 'SHA-384'])), h('label', {}, t('Authentication password'), password('authPassword', old && old.authPasswordSet))); const privBox = h('div', {class: 'row'}, h('label', {}, t('Encryption'), select('priv', ['AES', 'AES-256'], tg.priv, ['AES-128', 'AES-256'])), h('label', {}, t('Encryption password'), password('privPassword', old && old.privPasswordSet))); const level = select('level', ['authPriv', 'authNoPriv', 'noAuthNoPriv'], tg.level, [t('Authentication and encryption'), t('Authentication only'), t('Neither (not recommended)')]); const v3 = h('div', {}, h('div', {class: 'row'}, h('label', {}, t('User'), h('input', {name: 'user', value: tg.user, maxlength: 32})), h('label', {}, t('Security level'), level)), authBox, privBox, h('p', {class: 'hint'}, t('AES-256 needs SHA-256 or SHA-384.'))); const version = select('version', ['3', '2c', '1'], tg.version, ['SNMPv3', 'SNMPv2c', 'SNMPv1']); const update = () => { const is3 = version.value === '3'; community.hidden = is3; v3.hidden = !is3; authBox.hidden = level.value === 'noAuthNoPriv'; privBox.hidden = level.value !== 'authPriv'; }; version.addEventListener('change', update); level.addEventListener('change', update); update(); return [ h('div', {class: 'row'}, h('label', {}, t('Host'), h('input', {name: 'host', value: tg.host, required: true})), h('label', {}, t('Port'), h('input', {name: 'port', type: 'number', min: 1, max: 65535, value: tg.port, required: true}))), h('p', {class: 'hint'}, t('Host name or IP address of the network management station.')), h('div', {class: 'row'}, h('label', {}, t('Version'), h('select', {name: 'version'}, ['2c', '1'].map(v => h('option', {value: v, selected: v === tg.version}, 'SNMPv' + v)))), h('label', {}, t('Community'), h('input', {name: 'community', value: tg.community, required: true, maxlength: 255}))), ], h('label', {}, t('Version'), version), community, v3, ]; }, onSubmit: d => { const targets = [...data.settings.targets]; const n = {host: d.host.trim(), port: Number(d.port), version: d.version, community: d.community}; const n = {host: d.host.trim(), port: Number(d.port), version: d.version}; if (d.version === '3') Object.assign(n, {user: d.user.trim(), level: d.level, auth: d.auth, priv: d.priv, authPassword: d.authPassword, privPassword: d.privPassword}); else n.community = d.community; if (old) targets[index] = n; else targets.push(n); return save({targets}, t('Target saved.')); Loading @@ -149,6 +203,17 @@ load(); } const levelText = {authPriv: 'authPriv', authNoPriv: 'authNoPriv', noAuthNoPriv: 'noAuthNoPriv'}; function security(tg) { if (tg.version !== '3') return [h('span', {class: 'badge warn'}, t('clear text')), ' ', h('span', {class: 'mono'}, tg.community)]; const strong = tg.level === 'authPriv'; return [h('span', {class: 'badge ' + (strong ? 'ok' : 'warn')}, levelText[tg.level] || tg.level), ' ', h('span', {class: 'mono'}, tg.user), tg.level !== 'noAuthNoPriv' ? h('span', {class: 'muted'}, ' ' + [tg.auth, strong ? tg.priv : null].filter(Boolean).join(' / ')) : null]; } function draw() { const s = data.settings, st = data.status; const row = (label, value) => h('tr', {}, h('th', {}, label), h('td', {}, value)); Loading @@ -170,7 +235,9 @@ row(t('Status'), st.lastReport ? badge(st.status) : '–'), st.problems.length ? row(t('Not collected'), st.problems.join('; ')) : null, row(t('Notifications sent'), String(st.sent || 0)), row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')))))), row(t('Enterprise OID'), h('span', {class: 'mono'}, s.enterprise || '')), row(t('SNMPv3 engine ID'), [h('span', {class: 'mono'}, '0x' + (s.engineId || '')), st.engineBoots ? h('span', {class: 'muted'}, ' ' + t('(boots {0})', st.engineBoots)) : null]))))), h('section', {class: 'panel'}, h('div', {class: 'toolbar'}, h('h2', {}, t('Targets (NMS)')), Loading @@ -179,7 +246,7 @@ {title: t('Host'), render: tg => h('strong', {}, tg.host)}, {title: t('Port'), render: tg => tg.port, class: 'mono'}, {title: t('Version'), render: tg => 'SNMPv' + tg.version}, {title: t('Community'), render: tg => h('span', {class: 'mono'}, tg.community)}, {title: t('Security'), render: security}, {title: t('Sent'), render: tg => String((st.targets.find(x => x.target === key(tg)) || {}).sent || 0)}, {title: t('Error'), render: tg => { const e = (st.targets.find(x => x.target === key(tg)) || {}).error; Loading @@ -191,6 +258,9 @@ h('button', {class: 'small danger', onclick: () => removeTarget(i)}, t('Remove'))]; }}, ], s.targets, t('No targets yet.')), h('p', {class: 'hint'}, t('SNMPv3: the NMS knows each user under the engine ID of snmpdd, e.g. in snmptrapd.conf:')), h('pre', {class: 'log'}, 'createUser -e 0x' + (s.engineId || '…') + ' <' + t('user') + '> SHA-256 <' + t('password') + '> AES <' + t('password') + '>'), h('p', {class: 'hint'}, t('SNMPDD-MIB describes the notifications (/usr/share/snmp/mibs/SNMPDD-MIB.txt); load it into the NMS.')))); } Loading