mirror of
https://github.com/xcat2/confluent.git
synced 2026-01-11 18:42:29 +00:00
Allow specifiying SNMP privacy protocol
Modern SNMP devices may require AES. Unfortunately, older ones may refuse AES. For compatibility, continue to default to DES, but allow AES to be indicated in attributes.
This commit is contained in:
@@ -605,6 +605,10 @@ node = {
|
||||
'description': ('SNMPv1 community string, it is highly recommended to'
|
||||
'step up to SNMPv3'),
|
||||
},
|
||||
'snmp.privacyprotocol': {
|
||||
'description': 'The privacy protocol to use for SNMPv3',
|
||||
'valid_values': ('aes', 'des'),
|
||||
},
|
||||
# 'secret.snmplocalizedkey': {
|
||||
# 'description': ("SNMPv3 key localized to this node's SNMP Engine id"
|
||||
# 'This can be used in lieu of snmppassphrase to avoid'
|
||||
|
||||
@@ -255,7 +255,13 @@ def _extract_neighbor_data_b(args):
|
||||
|
||||
args are carried as a tuple, because of eventlet convenience
|
||||
"""
|
||||
switch, password, user, cfm, force = args[:5]
|
||||
# Safely unpack args with defaults to avoid IndexError
|
||||
switch = args[0] if len(args) > 0 else None
|
||||
password = args[1] if len(args) > 1 else None
|
||||
user = args[2] if len(args) > 2 else None
|
||||
cfm = args[3] if len(args) > 3 else None
|
||||
privproto = args[4] if len(args) > 4 else None
|
||||
force = args[5] if len(args) > 5 else False
|
||||
vintage = _neighdata.get(switch, {}).get('!!vintage', 0)
|
||||
now = util.monotonic_time()
|
||||
if vintage > (now - 60) and not force:
|
||||
@@ -265,7 +271,7 @@ def _extract_neighbor_data_b(args):
|
||||
return _extract_neighbor_data_https(switch, user, password, cfm, lldpdata)
|
||||
except Exception as e:
|
||||
pass
|
||||
conn = snmp.Session(switch, password, user)
|
||||
conn = snmp.Session(switch, password, user, privacy_protocol=privproto)
|
||||
sid = None
|
||||
for sysid in conn.walk('1.3.6.1.2.1.1.2'):
|
||||
sid = str(sysid[1][6:])
|
||||
@@ -364,8 +370,8 @@ def _extract_neighbor_data(args):
|
||||
return _extract_neighbor_data_b(args)
|
||||
except Exception as e:
|
||||
yieldexc = False
|
||||
if len(args) >= 6:
|
||||
yieldexc = args[5]
|
||||
if len(args) >= 7:
|
||||
yieldexc = args[6]
|
||||
if yieldexc:
|
||||
return e
|
||||
else:
|
||||
|
||||
@@ -213,14 +213,14 @@ def _fast_backend_fixup(macs, switch):
|
||||
else:
|
||||
_nodesbymac[mac] = (nodename, nummacs)
|
||||
|
||||
def _offload_map_switch(switch, password, user):
|
||||
def _offload_map_switch(switch, password, user, privprotocol=None):
|
||||
if _offloader is None:
|
||||
_start_offloader()
|
||||
evtid = random.randint(0, 4294967295)
|
||||
while evtid in _offloadevts:
|
||||
evtid = random.randint(0, 4294967295)
|
||||
_offloadevts[evtid] = eventlet.Event()
|
||||
_offloader.stdin.write(msgpack.packb((evtid, switch, password, user),
|
||||
_offloader.stdin.write(msgpack.packb((evtid, switch, password, user, privprotocol),
|
||||
use_bin_type=True))
|
||||
_offloader.stdin.flush()
|
||||
result = _offloadevts[evtid].wait()
|
||||
@@ -280,12 +280,11 @@ def _map_switch_backend(args):
|
||||
# fallback if ifName is empty
|
||||
#
|
||||
global _macmap
|
||||
if len(args) == 4:
|
||||
switch, password, user, _ = args # 4th arg is for affluent only
|
||||
if not user:
|
||||
user = None
|
||||
else:
|
||||
switch, password = args
|
||||
switch = args[0] if len(args) > 0 else None
|
||||
password = args[1] if len(args) > 1 else None
|
||||
user = args[2] if len(args) > 2 else None
|
||||
privprotocol = args[4] if len(args) > 4 else None
|
||||
if not user: # make '' be treated as None
|
||||
user = None
|
||||
if switch not in noaffluent:
|
||||
try:
|
||||
@@ -298,7 +297,7 @@ def _map_switch_backend(args):
|
||||
except Exception as e:
|
||||
pass
|
||||
mactobridge, ifnamemap, bridgetoifmap = _offload_map_switch(
|
||||
switch, password, user)
|
||||
switch, password, user, privprotocol)
|
||||
maccounts = {}
|
||||
bridgetoifvalid = False
|
||||
for mac in mactobridge:
|
||||
@@ -367,9 +366,9 @@ def _map_switch_backend(args):
|
||||
_nodesbymac[mac] = (nodename, maccounts[ifname])
|
||||
_macsbyswitch[switch] = newmacs
|
||||
|
||||
def _snmp_map_switch_relay(rqid, switch, password, user):
|
||||
def _snmp_map_switch_relay(rqid, switch, password, user, privprotocol=None):
|
||||
try:
|
||||
res = _snmp_map_switch(switch, password, user)
|
||||
res = _snmp_map_switch(switch, password, user, privprotocol)
|
||||
payload = msgpack.packb((rqid,) + res, use_bin_type=True)
|
||||
try:
|
||||
sys.stdout.buffer.write(payload)
|
||||
@@ -391,10 +390,10 @@ def _snmp_map_switch_relay(rqid, switch, password, user):
|
||||
finally:
|
||||
sys.stdout.flush()
|
||||
|
||||
def _snmp_map_switch(switch, password, user):
|
||||
def _snmp_map_switch(switch, password, user, privprotocol=None):
|
||||
haveqbridge = False
|
||||
mactobridge = {}
|
||||
conn = snmp.Session(switch, password, user)
|
||||
conn = snmp.Session(switch, password, user, privacy_protocol=privprotocol)
|
||||
ifnamemap = get_portnamemap(conn)
|
||||
for vb in conn.walk('1.3.6.1.2.1.17.7.1.2.2.1.2'):
|
||||
haveqbridge = True
|
||||
|
||||
@@ -21,7 +21,7 @@ import confluent.collective.manager as collective
|
||||
def get_switchcreds(configmanager, switches):
|
||||
switchcfg = configmanager.get_node_attributes(
|
||||
switches, ('secret.hardwaremanagementuser', 'secret.snmpcommunity',
|
||||
'secret.hardwaremanagementpassword',
|
||||
'secret.hardwaremanagementpassword', 'snmp.privacyprotocol',
|
||||
'collective.managercandidates'), decrypt=True)
|
||||
switchauth = []
|
||||
for switch in switches:
|
||||
@@ -47,7 +47,9 @@ def get_switchcreds(configmanager, switches):
|
||||
'secret.hardwaremanagementuser', {}).get('value', None)
|
||||
if not user:
|
||||
user = None
|
||||
switchauth.append((switch, password, user, configmanager))
|
||||
privacy_protocol = switchparms.get(
|
||||
'snmp.privacyprotocol', {}).get('value', None)
|
||||
switchauth.append((switch, password, user, configmanager, privacy_protocol))
|
||||
return switchauth
|
||||
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ def _get_transport(name):
|
||||
|
||||
class Session(object):
|
||||
|
||||
def __init__(self, server, secret, username=None, context=None):
|
||||
def __init__(self, server, secret, username=None, context=None, privacy_protocol=None):
|
||||
"""Create a new session to interrogate a switch
|
||||
|
||||
If username is not given, it is assumed that
|
||||
@@ -97,9 +97,17 @@ class Session(object):
|
||||
# SNMP v2c
|
||||
self.authdata = snmp.CommunityData(secret, mpModel=1)
|
||||
else:
|
||||
if privacy_protocol == 'aes':
|
||||
privproto = snmp.usmAesCfb128Protocol
|
||||
elif privacy_protocol in ('des', None):
|
||||
privproto = snmp.usmDESPrivProtocol
|
||||
else:
|
||||
raise exc.ConfluentException('Unsupported SNMPv3 privacy protocol '
|
||||
'{0}'.format(privacy_protocol))
|
||||
self.authdata = snmp.UsmUserData(
|
||||
username, authKey=secret, privKey=secret,
|
||||
authProtocol=snmp.usmHMACSHAAuthProtocol)
|
||||
authProtocol=snmp.usmHMACSHAAuthProtocol,
|
||||
privProtocol=privproto)
|
||||
self.eng = snmp.SnmpEngine()
|
||||
|
||||
def walk(self, oid):
|
||||
|
||||
Reference in New Issue
Block a user