#!/usr/bin/env python3""" IPv6 获取脚本直接调用 API 获取设备 IPv6 地址"""import requestsimport jsonimport sysimport hashlibimport base64# 配置ROUTER_IP = "你的路由器IP"USERNAME = "用户名"PASSWORD = "密码"BASE_URL = f"http://{ROUTER_IP}"def encrypt_password(password): """ 密码加密方式: 1. passwd: MD5(password) 2. pass: Base64("salt_11" + password) """ # MD5 哈希 passwd_md5 = hashlib.md5(password.encode()).hexdigest() # Base64 编码 (salt_11 + password) pass_base64 = base64.b64encode(f"salt_11{password}".encode()).decode() return passwd_md5, pass_base64class API: def __init__(self): self.session = requests.Session() self.cookie = None def login(self): """登录 路由器""" url = f"{BASE_URL}/Action/login" # 加密密码 passwd_md5, pass_base64 = encrypt_password(PASSWORD) # 登录使用 JSON 格式,密码需要加密 payload = { "username": USERNAME, "passwd": passwd_md5, "pass": pass_base64, "remember_password": None } try: response = self.session.post( url, json=payload, headers={ "Content-Type": "application/json;charset=UTF-8", "Accept": "application/json, text/plain, */*", "Origin": BASE_URL, "Referer": f"{BASE_URL}/login" }, timeout=10 ) result = response.json() if result.get("Result") == 10000: self.cookie = response.cookies.get("sess_key") print(f"登录成功") return True else: print(f"登录失败: {result}") return False except Exception as e: print(f"登录错误: {e}") return False def get_ipv6_devices(self): """获取 IPv6 设备列表""" if not self.cookie: if not self.login(): return None url = f"{BASE_URL}/Action/call" # API 调用参数 - 正确的 func_name 和参数 payload = { "func_name": "monitor_lanipv6", "action": "show", "param": { "TYPE": "data,total", "ORDER_BY": "ip_addr_int", "orderType": "IP", "limit": "0,20", "ORDER": "" } } headers = { "Content-Type": "application/json;charset=UTF-8", "Accept": "application/json, text/plain, */*", "Origin": BASE_URL, "Referer": f"{BASE_URL}/" } # 手动设置 cookie,确保包含所有必要的字段 cookies = { "username": USERNAME, "sess_key": self.cookie, "login": "1" } try: response = self.session.post( url, json=payload, headers=headers, cookies=cookies, timeout=10 ) result = response.json() if result.get("Result") == 30000: # 成功返回码是 30000 return result.get("Data", {}).get("data", []) else: print(f"获取数据失败: {result}") return None except Exception as e: print(f"获取数据错误: {e}") return None def format_output(self, devices): """格式化输出""" if not devices: print("没有找到 IPv6 设备") return print(f"\n{'='*60}") print(f"📡 路由器 IPv6 设备列表") print(f"{'='*60}\n") for i, device in enumerate(devices, 1): hostname = device.get('hostname', '未命名') ipv6 = device.get('ip_addr', 'N/A') mac = device.get('mac', 'N/A') link_addr = device.get('link_addr', 'N/A') uptime = device.get('uptime', 'N/A') connect_num = device.get('connect_num', 0) total_up = device.get('total_up', 0) total_down = device.get('total_down', 0) # 转换流量为可读格式 total_up_gb = total_up / (1024**3) total_down_gb = total_down / (1024**3) print(f"设备 {i}: {hostname}") print(f" 🌐 IPv6: {ipv6}") print(f" 🔗 Link-local: {link_addr}") print(f" 📍 MAC: {mac}") print(f" ⏱️ 上线时间: {uptime}") print(f" 🔗 连接数: {connect_num}") print(f" 📊 流量: 上行 {total_up_gb:.2f} GB / 下行 {total_down_gb:.2f} GB") print() print(f"共 {len(devices)} 台设备在线") print(f"{'='*60}\n")def main(): import argparse parser = argparse.ArgumentParser(description='IPv6 获取工具') parser.add_argument('--json', action='store_true', help='以 JSON 格式输出') parser.add_argument('--host', type=str, help='指定设备主机名') args = parser.parse_args() api = API() devices = api.get_ipv6_devices() if not devices: print("获取设备列表失败") sys.exit(1) # 如果指定了主机名,只显示该设备 if args.host: devices = [d for d in devices if args.host.lower() in d.get('hostname', '').lower()] if not devices: print(f"未找到主机名为 '{args.host}' 的设备") sys.exit(1) # JSON 输出 if args.json: output = [] for d in devices: output.append({ 'hostname': d.get('hostname', ''), 'ipv6': d.get('ip_addr', ''), 'mac': d.get('mac', ''), 'link_local': d.get('link_addr', '') }) print(json.dumps(output, indent=2, ensure_ascii=False)) else: api.format_output(devices)if __name__ == "__main__": main()