Source code for peat.modules.sel.sel_3620
"""
SEL-3620 Ethernet Security Gateway.
Note: "This device accepts HTTPS connections only and will reject all HTTP connection requests. "
Authors
- Amanda Gonzales
- James Gallagher
"""
from peat import DeviceData, DeviceModule, IPMethod, exit_handler
from .sel_http import SELHTTP
[docs]
class SEL3620(DeviceModule):
"""
SEL-3620 Ethernet Security Gateway.
"""
device_type = "Gateway"
vendor_id = "SEL"
vendor_name = "Schweitzer Engineering Laboratories"
brand = "SEL"
module_aliases = ["sel-3620", "3620"]
default_options = {
"web": {
"user": "",
"pass": "",
"users": [
"admin",
"Admin",
"administrator",
],
}
}
@classmethod
def _verify_http(cls, dev: DeviceData) -> bool:
"""
Verify a device is a SEL-3620 Gateway via the HTTPS web interface.
"""
port = dev.options["https"]["port"]
timeout = dev.options["https"]["timeout"]
cls.log.debug(
f"Verifying SEL-3620 HTTP for {dev.ip}:{port} using HTTPS (timeout: {timeout})"
)
session = SELHTTP(dev.ip, port, timeout)
logged_in = False
if dev._cache.get("verified_web_user") and dev._cache.get("verified_web_pass"):
logged_in = session.login_3620(
dev._cache["verified_web_user"],
dev._cache["verified_web_pass"],
)
# Check all user, and pass, only proceed when logged_in is True, or exhausted
else:
if dev.options["web"]["user"]:
users = [dev.options["web"]["user"]]
else:
users = dev.options["web"]["users"]
if dev.options["web"]["pass"]:
passwords = [dev.options["web"]["pass"]]
else:
passwords = dev.options["web"]["passwords"]
for username in users:
cls.log.debug(f"Attempting SEL-3620 login to {dev.ip} with user '{username}'")
for password in passwords:
logged_in = session.login_3620(username, password)
if logged_in:
dev._cache["verified_web_user"] = username
dev._cache["verified_web_pass"] = password
dev.related.user.add(username)
break
if logged_in:
break
if logged_in:
try:
dashboard = session.get_index(dev=dev)
except Exception:
cls.log.exception(f"Failed to view dashboard for {dev.ip}")
session.disconnect()
return False
# Check if dashboard has appropriate fields
if ("web_device_info" not in dashboard) or (
"Firmware Version" not in dashboard["web_device_info"]
):
session.disconnect()
return False
# TODO: don't hardcode check to 3620, process_fid() should set model #
if (
"3620" in dashboard["web_device_info"]["Firmware Version"]
# and "3620" in dashboard["web_device_info"]["Host Name"]
):
# Cache the session using this protocol
if not dev._cache.get("web_session"):
dev._cache["web_session"] = session
exit_handler.register(session.disconnect, "CONNECTION")
else:
session.disconnect()
return True
session.disconnect()
cls.log.debug(f"SEL3620 HTTPS verification failed for {dev.ip}:{port}")
return False
@classmethod
def _pull(cls, dev: DeviceData) -> bool:
cls.log.info(f"Pulling web pages from {dev.ip}")
session = dev._cache["web_session"]
# TODO: explicit list of functions to call
# TODO: return false if all functions fail
methods = [
k
for k, f in SELHTTP.__dict__.items()
if callable(f) and f.__name__.startswith("gateway_")
]
cls.log.debug(f"Get Requests for {len(methods)} HTTP methods...")
for name in methods:
cls.log.info(f"** Getting: {name} **")
try:
res = getattr(session, name)(dev)
if not res:
cls.log.warning(f"False result for method '{name}'")
except Exception as ex:
cls.log.error(f"{name}: {ex!s}")
return True
SEL3620.ip_methods = [
IPMethod(
name="sel_3620_web_fingerprint",
description=str(SEL3620._verify_http.__doc__).strip(),
type="unicast_ip",
identify_function=SEL3620._verify_http,
default_port=443,
protocol="https",
reliability=6, # Should find title for 3620 on login page
transport="tcp",
)
]
__all__ = ["SEL3620"]