commit f10ceb07f1d9b69afd6eeea8759233fdf986c2a2 Author: Gregor Michels Date: Thu Jun 26 21:47:46 2025 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c790e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +environment/ diff --git a/environment.txt b/environment.txt new file mode 100644 index 0000000..9102a7f --- /dev/null +++ b/environment.txt @@ -0,0 +1,5 @@ +certifi==2025.6.15 +charset-normalizer==3.4.2 +idna==3.10 +requests==2.32.4 +urllib3==2.5.0 diff --git a/main.py b/main.py new file mode 100755 index 0000000..b03405f --- /dev/null +++ b/main.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 + +from bs4 import BeautifulSoup +import time +import requests +import pdb +import os +import random +import re +from enum import Enum + +IP = "192.168.42.100" + + +class VLAN_PORT_MODE(Enum): + GENERAL = 0 + ACCESS = 1 + TRUNK = 2 + DOT1QTUNNEL = 3 + + +class VLAN_PORT_ACL(Enum): + EXCLUDED = 0 + FORBIDDEN = 1 + TAGGED = 2 + UNTAGGED = 3 + + +def zyxel_password(pw: str) -> str: + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + result = "" + l = len(pw) + + for i in range(1, 322 - len(pw)): + if i % 5 == 0 and l > 0: + l -= 1 + result += pw[l] + elif i == 123: + if len(pw) < 10: + result += "0" + else: + c = str(len(pw) // 10) + result += c + elif i == 289: + result += str(len(pw) % 10) + else: + rnd = random.choice(list(alphabet)) + result += rnd + return result + + +def get_login_cookie(host: str, username: str, password: str) -> str: + auth_id = requests.get( + f"http://{host}/cgi-bin/dispatcher.cgi", + params={"login": 1, "username": username, "password": zyxel_password(password)}, + ) + + if auth_id.status_code != 200: + raise Exception("error while getting auth_id {auth_id.text}") + + time.sleep(0.5) + + cookie = requests.post( + f"http://{host}/cgi-bin/dispatcher.cgi", + data={"authId": auth_id.text.strip(), "login_chk": "true"}, + ) + + if cookie.text.strip() != "OK,": + raise Exception("error while getting cookie {cookie.text}") + + return cookie.cookies.get("HTTP_XSSID") + + +def get_cmd(host: str, xssid: str, cmd: int, **params) -> str: + params.update({"cmd": cmd}) + return requests.get( + f"http://{host}/cgi-bin/dispatcher.cgi", + params=params, + cookies={"HTTP_XSSID": xssid}, + ).text + + +def get_vlans(response: str) -> dict: + soup = BeautifulSoup(response, "html.parser") + + data = {} + table_body = soup.find("table", attrs={"width": "560"}) + + rows = table_body.find_all("tr") + for row in rows[1:]: + cols = row.find_all("td") + cols = [ele.text.strip() for ele in cols] + + try: + _, vlan_id, vlan_name, vlan_type, _, _ = cols + data.update( + { + vlan_id: { + "name": vlan_name, + "type": vlan_type, + } + } + ) + except ValueError: + continue + + return data + + +def parse_vlan_ports(response: str) -> dict: + soup = BeautifulSoup(response, "html.parser") + + data = {} + # + port_settings = soup.find_all( + "input", attrs={"type": "hidden", "id": re.compile(r"vlanMode_\d+")} + ) + for port_setting in port_settings: + port = port_setting.find_previous().text.strip() + port_type = int(port_setting.attrs.get("value")) + + acl = list( + filter( + lambda p: "checked" in p.attrs, + port_setting.find_next().find_all("input"), + ) + )[0] + + data.update( + { + port: { + "mode": VLAN_PORT_MODE(port_type), + "acl": VLAN_PORT_ACL(int(acl.attrs.get("value"))), + } + } + ) + + return data + + +def extract_data_from_table(response: str) -> dict: + soup = BeautifulSoup(response, "html.parser") + + data = {} + table_body = soup.find_all("table")[-1] + + rows = table_body.find_all("tr") + keys = [ele.text.strip() for ele in rows[0].find_all("td")] + entries = [] + for row in rows[1:]: + cols = row.find_all("td") + cols = [ele.text.strip() for ele in cols] + entries.append({k: v for (k, v) in zip(keys, cols) if k.strip() != ""}) + + return list(filter(lambda e: e, entries)) + + +def dictify(data: list, key: str) -> dict: + result = {} + for d in data: + k = d[key] + del d[key] + result.update({k: d}) + return result + + +if __name__ == "__main__": + + cookie = get_login_cookie(IP, "admin", os.environ.get("ADMIN_PW")) + + print(parse_vlan_ports(get_cmd(IP, cookie, 1293, vid=2))) + + # print(dictify(extract_data_from_table(get_cmd(IP, cookie, 1283)), "VLAN ID")) + # print(dictify(extract_data_from_table(get_cmd(IP, cookie, 1290)), "Port")) + + # vlans = get_vlans(get_cmd(IP, cookie, 1283)) + # print(vlans)