Page MenuHomeVyOS Platform

No OneTemporary

Size
38 KB
Referenced Files
None
Subscribers
None
diff --git a/interface-definitions/service_snmp.xml.in b/interface-definitions/service_snmp.xml.in
index f23151ef9..cc21f5b8b 100644
--- a/interface-definitions/service_snmp.xml.in
+++ b/interface-definitions/service_snmp.xml.in
@@ -1,599 +1,598 @@
<?xml version="1.0"?>
<!-- SNMP forwarder configuration -->
<interfaceDefinition>
<node name="service">
<children>
<node name="snmp" owner="${vyos_conf_scripts_dir}/service_snmp.py">
<properties>
<help>Simple Network Management Protocol (SNMP)</help>
<priority>900</priority>
</properties>
<children>
<tagNode name="community">
<properties>
<help>Community name</help>
<constraint>
<regex>[[:alnum:]-_!@*#]{1,100}</regex>
</constraint>
<constraintErrorMessage>Community string is limited to alphanumerical characters, -, _, !, @, *, and # with a total lenght of 100</constraintErrorMessage>
</properties>
<children>
<leafNode name="authorization">
<properties>
<help>Authorization type</help>
<completionHelp>
<list>ro rw</list>
</completionHelp>
<valueHelp>
<format>ro</format>
<description>Read-Only</description>
</valueHelp>
<valueHelp>
<format>rw</format>
<description>Read-Write</description>
</valueHelp>
<constraint>
<regex>(ro|rw)</regex>
</constraint>
<constraintErrorMessage>Authorization type must be either 'rw' or 'ro'</constraintErrorMessage>
</properties>
<defaultValue>ro</defaultValue>
</leafNode>
<leafNode name="client">
<properties>
<help>IP address of SNMP client allowed to contact system</help>
<constraint>
<validator name="ipv4-address"/>
<validator name="ipv6-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="network">
<properties>
<help>Subnet of SNMP client(s) allowed to contact system</help>
<valueHelp>
<format>ipv4net</format>
<description>IP address and prefix length</description>
</valueHelp>
<valueHelp>
<format>ipv6net</format>
<description>IPv6 address and prefix length</description>
</valueHelp>
<constraint>
<validator name="ip-prefix"/>
</constraint>
<multi/>
</properties>
<defaultValue>0.0.0.0/0 ::/0</defaultValue>
</leafNode>
</children>
</tagNode>
<leafNode name="contact">
<properties>
<help>Contact information</help>
<constraint>
<regex>.{1,255}</regex>
</constraint>
<constraintErrorMessage>Contact information is limited to 255 characters or less</constraintErrorMessage>
</properties>
</leafNode>
#include <include/generic-description.xml.i>
<node name="mib">
<properties>
<help>Management information base (MIB)</help>
</properties>
<children>
<leafNode name="interface-max">
<properties>
<help>Sets the maximum number of interfaces included in IF-MIB data collection</help>
<valueHelp>
<format>u32:1-4294967295</format>
<description>Sets the maximum number of interfaces included in IF-MIB data collection</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-4294967295"/>
</constraint>
</properties>
</leafNode>
<leafNode name="interface">
<properties>
<help>Sets the interface name prefix to include in the IF-MIB data collection</help>
<completionHelp>
<list>br bond dum eth gnv macsec peth sstpc tun veth vti vtun vxlan wg wlan wwan</list>
</completionHelp>
<valueHelp>
<format>br</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>bond</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>dum</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>eth</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>gnv</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>macsec</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>peth</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>sstpc</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>tun</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>veth</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>vti</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>vtun</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>vxlan</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>wg</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>wlan</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<valueHelp>
<format>wwan</format>
<description>Allow prefix for IF-MIB data collection</description>
</valueHelp>
<constraint>
<regex>(br|bond|dum|eth|gnv|macsec|peth|sstpc|tun|veth|vti|vtun|vxlan|wg|wlan|wwan)</regex>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</node>
<tagNode name="listen-address">
<properties>
<help>IP address to listen for incoming SNMP requests</help>
<completionHelp>
<script>${vyos_completion_dir}/list_local_ips.sh --both</script>
</completionHelp>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address to listen for incoming SNMP requests</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address to listen for incoming SNMP requests</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
<children>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>161</defaultValue>
</leafNode>
</children>
</tagNode>
<leafNode name="location">
<properties>
<help>Location information</help>
<constraint>
<regex>.{1,255}</regex>
</constraint>
<constraintErrorMessage>Location is limited to 255 characters or less</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="oid-enable">
<properties>
<help>Enable specific OIDs that by default are disable</help>
<completionHelp>
<list>ip-forward ip-route-table ip-net-to-media-table ip-net-to-physical-phys-address</list>
</completionHelp>
<valueHelp>
<format>ip-forward</format>
<description>Enable ipForward: .1.3.6.1.2.1.4.24</description>
</valueHelp>
<valueHelp>
<format>ip-route-table</format>
<description>Enable ipRouteTable: .1.3.6.1.2.1.4.21</description>
</valueHelp>
<valueHelp>
<format>ip-net-to-media-table</format>
<description>Enable ipNetToMediaTable: .1.3.6.1.2.1.4.22</description>
</valueHelp>
<valueHelp>
<format>ip-net-to-physical-phys-address</format>
<description>Enable ipNetToPhysicalPhysAddress: .1.3.6.1.2.1.4.35</description>
</valueHelp>
<constraint>
<regex>(ip-forward|ip-route-table|ip-net-to-media-table|ip-net-to-physical-phys-address)</regex>
</constraint>
<constraintErrorMessage>OID must be one of the liste options</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
#include <include/protocol-tcp-udp.xml.i>
<leafNode name="smux-peer">
<properties>
<help>Register a subtree for SMUX-based processing</help>
<valueHelp>
<format>txt</format>
<description>SNMP Object Identifier</description>
</valueHelp>
<multi/>
</properties>
</leafNode>
<leafNode name="trap-source">
<properties>
<help>SNMP trap source address</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
</leafNode>
<tagNode name="trap-target">
<properties>
<help>Address of trap target</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
<children>
<leafNode name="community">
<properties>
<help>Community used when sending trap information</help>
</properties>
</leafNode>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>162</defaultValue>
</leafNode>
</children>
</tagNode>
<node name="v3">
<properties>
<help>Simple Network Management Protocol (SNMP) v3</help>
</properties>
<children>
<leafNode name="engineid">
<properties>
<help>Specifies the EngineID that uniquely identify an agent (e.g. 000000000000000000000002)</help>
<constraint>
<regex>([0-9a-f][0-9a-f]){1,18}</regex>
</constraint>
<constraintErrorMessage>ID must contain an even number (from 2 to 36) of hex digits</constraintErrorMessage>
</properties>
- <defaultValue></defaultValue>
</leafNode>
<tagNode name="group">
<properties>
<help>Specifies the group with name groupname</help>
</properties>
<children>
#include <include/snmp/access-mode.xml.i>
<leafNode name="seclevel">
<properties>
<help>Security levels</help>
<completionHelp>
<list>noauth auth priv</list>
</completionHelp>
<valueHelp>
<format>noauth</format>
<description>Messages not authenticated and not encrypted (noAuthNoPriv)</description>
</valueHelp>
<valueHelp>
<format>auth</format>
<description>Messages are authenticated but not encrypted (authNoPriv)</description>
</valueHelp>
<valueHelp>
<format>priv</format>
<description>Messages are authenticated and encrypted (authPriv)</description>
</valueHelp>
<constraint>
<regex>(noauth|auth|priv)</regex>
</constraint>
</properties>
<defaultValue>auth</defaultValue>
</leafNode>
<leafNode name="view">
<properties>
<help>Defines the name of view</help>
<completionHelp>
<path>service snmp v3 view</path>
</completionHelp>
</properties>
</leafNode>
</children>
</tagNode>
<tagNode name="trap-target">
<properties>
<help>Defines SNMP target for inform or traps for IP</help>
<valueHelp>
<format>ipv4</format>
<description>IP address of trap target</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address of trap target</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
<validator name="ipv6-address"/>
</constraint>
</properties>
<children>
<node name="auth">
<properties>
<help>Defines the privacy</help>
</properties>
<children>
<leafNode name="encrypted-password">
<properties>
<help>Defines the encrypted key for authentication</help>
<constraint>
<regex>[0-9a-f]*</regex>
</constraint>
<constraintErrorMessage>Encrypted key must only contain hex digits</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="plaintext-password">
<properties>
<help>Defines the clear text key for authentication</help>
<constraint>
<regex>.{8,}</regex>
</constraint>
<constraintErrorMessage>Key must contain 8 or more characters</constraintErrorMessage>
</properties>
</leafNode>
#include <include/snmp/authentication-type.xml.i>
</children>
</node>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>162</defaultValue>
</leafNode>
<node name="privacy">
<properties>
<help>Defines the privacy</help>
</properties>
<children>
<leafNode name="encrypted-password">
<properties>
<help>Defines the encrypted key for privacy protocol</help>
<constraint>
<regex>[0-9a-f]*</regex>
</constraint>
<constraintErrorMessage>Encrypted key must only contain hex digits</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="plaintext-password">
<properties>
<help>Defines the clear text key for privacy protocol</help>
<constraint>
<regex>.{8,}</regex>
</constraint>
<constraintErrorMessage>Key must contain 8 or more characters</constraintErrorMessage>
</properties>
</leafNode>
#include <include/snmp/privacy-type.xml.i>
</children>
</node>
#include <include/protocol-tcp-udp.xml.i>
<leafNode name="type">
<properties>
<help>Specifies the type of notification between inform and trap</help>
<completionHelp>
<list>inform trap</list>
</completionHelp>
<valueHelp>
<format>inform</format>
<description>Use INFORM</description>
</valueHelp>
<valueHelp>
<format>trap</format>
<description>Use TRAP</description>
</valueHelp>
<constraint>
<regex>(inform|trap)</regex>
</constraint>
</properties>
<defaultValue>inform</defaultValue>
</leafNode>
<leafNode name="user">
<properties>
<help>Defines username for authentication</help>
<completionHelp>
<path>service snmp v3 user</path>
</completionHelp>
</properties>
</leafNode>
</children>
</tagNode>
<tagNode name="user">
<properties>
<help>Specifies the user with name username</help>
<constraint>
<regex>[^\(\)\|\-]+</regex>
</constraint>
<constraintErrorMessage>Illegal characters in name</constraintErrorMessage>
</properties>
<children>
<node name="auth">
<properties>
<help>Specifies the auth</help>
</properties>
<children>
<leafNode name="encrypted-password">
<properties>
<help>Defines the encrypted key for authentication</help>
<constraint>
<regex>[0-9a-f]*</regex>
</constraint>
<constraintErrorMessage>Encrypted key must only contain hex digits</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="plaintext-password">
<properties>
<help>Defines the clear text key for authentication</help>
<constraint>
<regex>.{8,}</regex>
</constraint>
<constraintErrorMessage>Key must contain 8 or more characters</constraintErrorMessage>
</properties>
</leafNode>
#include <include/snmp/authentication-type.xml.i>
</children>
</node>
<leafNode name="group">
<properties>
<help>Specifies group for user name</help>
<completionHelp>
<path>service snmp v3 group</path>
</completionHelp>
</properties>
</leafNode>
#include <include/snmp/access-mode.xml.i>
<node name="privacy">
<properties>
<help>Defines the privacy</help>
</properties>
<children>
<leafNode name="encrypted-password">
<properties>
<help>Defines the encrypted key for privacy protocol</help>
<constraint>
<regex>[0-9a-f]*</regex>
</constraint>
<constraintErrorMessage>Encrypted key must only contain hex digits</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="plaintext-password">
<properties>
<help>Defines the clear text key for privacy protocol</help>
<constraint>
<regex>.{8,}</regex>
</constraint>
<constraintErrorMessage>Key must contain 8 or more characters</constraintErrorMessage>
</properties>
</leafNode>
#include <include/snmp/privacy-type.xml.i>
</children>
</node>
</children>
</tagNode>
<tagNode name="view">
<properties>
<help>Specifies the view with name viewname</help>
<constraint>
<regex>[^\(\)\|\-]+</regex>
</constraint>
<constraintErrorMessage>Illegal characters in name</constraintErrorMessage>
</properties>
<children>
<tagNode name="oid">
<properties>
<help>Specifies the oid</help>
<constraint>
<regex>[0-9]+(\.[0-9]+)*</regex>
</constraint>
<constraintErrorMessage>OID must start from a number</constraintErrorMessage>
</properties>
<children>
<leafNode name="exclude">
<properties>
<help>Exclude is an optional argument</help>
<multi/>
</properties>
</leafNode>
<leafNode name="mask">
<properties>
<help>Defines a bit-mask that is indicating which subidentifiers of the associated subtree OID should be regarded as significant</help>
<constraint>
<regex>[0-9a-f]{2}([\.:][0-9a-f]{2})*</regex>
</constraint>
<constraintErrorMessage>MASK is a list of hex octets, separated by '.' or ':'</constraintErrorMessage>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</tagNode>
</children>
</node>
<node name="script-extensions">
<properties>
<help>SNMP script extensions</help>
</properties>
<children>
<tagNode name="extension-name">
<properties>
<help>Extension name</help>
<constraint>
<regex>[a-z0-9\.\-\_]+</regex>
</constraint>
<constraintErrorMessage>Script extension contains invalid characters</constraintErrorMessage>
</properties>
<children>
<leafNode name="script">
<properties>
<help>Script location and name</help>
<completionHelp>
<script>ls /config/user-data</script>
</completionHelp>
<constraint>
<regex>[a-z0-9\.\-\_\/]+</regex>
</constraint>
<constraintErrorMessage>Script extension contains invalid characters</constraintErrorMessage>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
#include <include/interface/vrf.xml.i>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py
index d85f20820..c64c59af7 100755
--- a/src/conf_mode/service_snmp.py
+++ b/src/conf_mode/service_snmp.py
@@ -1,274 +1,277 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright (C) 2018-2025 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from sys import exit
from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.defaults import systemd_services
from vyos.snmpv3_hashgen import plaintext_to_md5
from vyos.snmpv3_hashgen import plaintext_to_sha1
from vyos.snmpv3_hashgen import random
from vyos.template import render
from vyos.utils.configfs import delete_cli_node
from vyos.utils.configfs import add_cli_node
from vyos.utils.dict import dict_search
from vyos.utils.network import is_addr_assigned
from vyos.utils.process import call
from vyos.utils.permission import chmod_755
from vyos.version import get_version_data
from vyos import ConfigError
from vyos import airbag
airbag.enable()
config_file_client = r'/etc/snmp/snmp.conf'
config_file_daemon = r'/etc/snmp/snmpd.conf'
config_file_access = r'/usr/share/snmp/snmpd.conf'
config_file_user = r'/var/lib/snmp/snmpd.conf'
default_script_dir = r'/config/user-data/'
systemd_override = r'/run/systemd/system/snmpd.service.d/override.conf'
systemd_service = systemd_services['snmpd']
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['service', 'snmp']
snmp = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
if not conf.exists(base):
snmp.update({'deleted' : ''})
if conf.exists(['service', 'lldp', 'snmp']):
snmp.update({'lldp_snmp' : ''})
if 'deleted' in snmp:
return snmp
version_data = get_version_data()
snmp['version'] = version_data['version']
# create an internal snmpv3 user of the form 'vyosxxxxxxxxxxxxxxxx'
snmp['vyos_user'] = 'vyos' + random(8)
snmp['vyos_user_pass'] = random(16)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
snmp = conf.merge_defaults(snmp, recursive=True)
if 'listen_address' in snmp:
# Always listen on localhost if an explicit address has been configured
# This is a safety measure to not end up with invalid listen addresses
# that are not configured on this system. See https://vyos.dev/T850
if '127.0.0.1' not in snmp['listen_address']:
tmp = {'127.0.0.1': {'port': '161'}}
snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
if '::1' not in snmp['listen_address']:
tmp = {'::1': {'port': '161'}}
snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
if 'script_extensions' in snmp and 'extension_name' in snmp['script_extensions']:
for key, val in snmp['script_extensions']['extension_name'].items():
if 'script' not in val:
continue
script_path = val['script']
# if script has not absolute path, use pre configured path
if not os.path.isabs(script_path):
script_path = os.path.join(default_script_dir, script_path)
snmp['script_extensions']['extension_name'][key]['script'] = script_path
return snmp
def verify(snmp):
if 'deleted' in snmp:
return None
if {'deleted', 'lldp_snmp'} <= set(snmp):
raise ConfigError('Can not delete SNMP service, as LLDP still uses SNMP!')
### check if the configured script actually exist
if 'script_extensions' in snmp and 'extension_name' in snmp['script_extensions']:
for extension, extension_opt in snmp['script_extensions']['extension_name'].items():
if 'script' not in extension_opt:
raise ConfigError(f'Script extension "{extension}" requires an actual script to be configured!')
tmp = extension_opt['script']
if not os.path.isfile(tmp):
Warning(f'script "{tmp}" does not exist!')
else:
chmod_755(extension_opt['script'])
if 'listen_address' in snmp:
for address in snmp['listen_address']:
# We only wan't to configure addresses that exist on the system.
# Hint the user if they don't exist
if 'vrf' in snmp:
vrf_name = snmp['vrf']
if not is_addr_assigned(address, vrf_name) and address not in ['::1','127.0.0.1']:
raise ConfigError(f'SNMP listen address "{address}" not configured in vrf "{vrf_name}"!')
elif not is_addr_assigned(address):
raise ConfigError(f'SNMP listen address "{address}" not configured in default vrf!')
if 'trap_target' in snmp:
for trap, trap_config in snmp['trap_target'].items():
if 'community' not in trap_config:
raise ConfigError(f'Trap target "{trap}" requires a community to be set!')
if 'oid_enable' in snmp:
Warning(f'Custom OIDs are enabled and may lead to system instability and high resource consumption')
verify_vrf(snmp)
# bail out early if SNMP v3 is not configured
if 'v3' not in snmp:
return None
if 'user' in snmp['v3']:
+ if 'engineid' not in snmp['v3']:
+ raise ConfigError(f'EngineID must be configured for SNMPv3!')
+
for user, user_config in snmp['v3']['user'].items():
if 'group' not in user_config:
raise ConfigError(f'Group membership required for user "{user}"!')
if 'plaintext_password' not in user_config['auth'] and 'encrypted_password' not in user_config['auth']:
raise ConfigError(f'Must specify authentication encrypted-password or plaintext-password for user "{user}"!')
if 'plaintext_password' not in user_config['privacy'] and 'encrypted_password' not in user_config['privacy']:
raise ConfigError(f'Must specify privacy encrypted-password or plaintext-password for user "{user}"!')
if 'group' in snmp['v3']:
for group, group_config in snmp['v3']['group'].items():
if 'seclevel' not in group_config:
raise ConfigError(f'Must configure "seclevel" for group "{group}"!')
if 'view' not in group_config:
raise ConfigError(f'Must configure "view" for group "{group}"!')
# Check if 'view' exists
view = group_config['view']
if 'view' not in snmp['v3'] or view not in snmp['v3']['view']:
raise ConfigError(f'You must create view "{view}" first!')
if 'view' in snmp['v3']:
for view, view_config in snmp['v3']['view'].items():
if 'oid' not in view_config:
raise ConfigError(f'Must configure an "oid" for view "{view}"!')
if 'trap_target' in snmp['v3']:
for trap, trap_config in snmp['v3']['trap_target'].items():
if 'plaintext_password' not in trap_config['auth'] and 'encrypted_password' not in trap_config['auth']:
raise ConfigError(f'Must specify one of authentication encrypted-password or plaintext-password for trap "{trap}"!')
if {'plaintext_password', 'encrypted_password'} <= set(trap_config['auth']):
raise ConfigError(f'Can not specify both authentication encrypted-password and plaintext-password for trap "{trap}"!')
if 'plaintext_password' not in trap_config['privacy'] and 'encrypted_password' not in trap_config['privacy']:
raise ConfigError(f'Must specify one of privacy encrypted-password or plaintext-password for trap "{trap}"!')
if {'plaintext_password', 'encrypted_password'} <= set(trap_config['privacy']):
raise ConfigError(f'Can not specify both privacy encrypted-password and plaintext-password for trap "{trap}"!')
if 'type' not in trap_config:
raise ConfigError('SNMP v3 trap "type" must be specified!')
return None
def generate(snmp):
# As we are manipulating the snmpd user database we have to stop it first!
# This is even save if service is going to be removed
call(f'systemctl stop {systemd_service}')
# Clean config files
config_files = [config_file_client, config_file_daemon,
config_file_access, config_file_user, systemd_override]
for file in config_files:
if os.path.isfile(file):
os.unlink(file)
if 'deleted' in snmp:
return None
if 'v3' in snmp:
# SNMPv3 uses a hashed password. If CLI defines a plaintext password,
# we will hash it in the background and replace the CLI node!
if 'user' in snmp['v3']:
for user, user_config in snmp['v3']['user'].items():
if dict_search('auth.type', user_config) == 'sha':
hash = plaintext_to_sha1
else:
hash = plaintext_to_md5
if dict_search('auth.plaintext_password', user_config) is not None:
tmp = hash(dict_search('auth.plaintext_password', user_config),
dict_search('v3.engineid', snmp))
snmp['v3']['user'][user]['auth']['encrypted_password'] = tmp
del snmp['v3']['user'][user]['auth']['plaintext_password']
cli_base = ['service', 'snmp', 'v3', 'user', user, 'auth']
delete_cli_node(cli_base + ['plaintext-password'])
add_cli_node(cli_base + ['encrypted-password'], value=tmp)
if dict_search('privacy.plaintext_password', user_config) is not None:
tmp = hash(dict_search('privacy.plaintext_password', user_config),
dict_search('v3.engineid', snmp))
snmp['v3']['user'][user]['privacy']['encrypted_password'] = tmp
del snmp['v3']['user'][user]['privacy']['plaintext_password']
cli_base = ['service', 'snmp', 'v3', 'user', user, 'privacy']
delete_cli_node(cli_base + ['plaintext-password'])
add_cli_node(cli_base + ['encrypted-password'], value=tmp)
# Write client config file
render(config_file_client, 'snmp/etc.snmp.conf.j2', snmp)
# Write server config file
render(config_file_daemon, 'snmp/etc.snmpd.conf.j2', snmp)
# Write access rights config file
render(config_file_access, 'snmp/usr.snmpd.conf.j2', snmp)
# Write access rights config file
render(config_file_user, 'snmp/var.snmpd.conf.j2', snmp)
# Write daemon configuration file
render(systemd_override, 'snmp/override.conf.j2', snmp)
return None
def apply(snmp):
# Always reload systemd manager configuration
call('systemctl daemon-reload')
if 'deleted' in snmp:
return None
# start SNMP daemon
call(f'systemctl reload-or-restart {systemd_service}')
return None
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:21 AM (21 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4653860
Default Alt Text
(38 KB)

Event Timeline