import re from librouteros import Api """ 配置步骤,每个步骤都可以安全幂等执行,配置混合节点的出口的函数可能会很慢,因为出口比较多 """ def configNet(conn: Api, config): """ 配置网络 """ try: # 配置路由 routes = conn.path("ip", "route") for route in routes: if route["routing-table"] == "1": try: routes.update(**{".id": route[".id"], "gateway": config["gateway"]}) except Exception as e: raise RuntimeError("更新默认路由失败: {}".format(e)) # 配置地址 addrs = conn.path("ip", "address") for addr in addrs: if addr["interface"] == "lan": try: addrs.update(**{".id": addr[".id"], "address": config["private"]}) except Exception as e: raise RuntimeError("更新 WAN 地址失败: {}".format(e)) # 刷新 mac 地址 eths = conn.path("interface", "ethernet") for eth in eths: if eth["name"] == "lan": tuple(eths("reset-mac-address", **{".id": eth[".id"]})) except Exception as e: raise RuntimeError(f"配置网络失败: {e}") # ==================== # 极狐配置 # ==================== def configJhOuts(conn: Api, config): """ 配置 vpn 出口负载均衡 """ try: count = 20 # 配置 ppp ppps = conn.path("interface", "l2tp-client") # 删除旧的 ppp for ppp in ppps: if ppp["name"].startswith("l2tp-out"): try: ppps.remove(ppp[".id"]) except Exception as e: raise RuntimeError("删除 PPP 失败: {}".format(e)) # 添加新的 ppp for i in range(1, count + 1): ppps.add( **{ "name": "l2tp-out{}".format(i), "connect-to": "192.168.25{}.25{}".format( (i - 1) % 3 + 1, (i - 1) % 3 + 1 ), "user": "jdzz{}dt{}".format(i, config["index"]), "password": "123231", "disabled": "no", } ) # 配置路由 routes = conn.path("ip", "route") # 删除旧的路由表 for route in routes: if str(route["routing-table"]).startswith("r"): try: routes.remove(route[".id"]) except Exception as e: raise RuntimeError("删除路由表失败: {}".format(e)) # 添加新的路由表 for i in range(1, count + 1): routeName = "r{}".format(i) routeOut = "l2tp-out{}".format(i) try: routes.add( **{ "dst-address": "0.0.0.0/0", "gateway": routeOut, "routing-table": routeName, } ) except Exception as e: raise RuntimeError(f"添加路由表失败: {e}") except Exception as e: raise RuntimeError(f"配置出口失败: {e}") def configJhMixOuts(conn: Api, config): """ 配置 vpn 出口负载均衡 (混合模式) """ try: ppps = conn.path("interface", "l2tp-client") for ppp in ppps: if ppp["name"].startswith("l2tp-out"): try: ppps.remove(ppp[".id"]) except Exception as e: raise RuntimeError("删除 PPP 失败: {}".format(e)) index = (int(config["index"]) - 1) * 10 for i in range(30): for j in range(10): n = j * 30 + i k = n % 3 + 1 ppps.add( **{ "name": f"l2tp-out{n + 1}", "connect-to": f"192.168.25{k}.25{k}", "user": f"jdzz{j + 1 + index}dt{i + 221}", "password": "123231", "disabled": "no", } ) routes = conn.path("ip", "route") for route in routes: if str(route["routing-table"]).startswith("r"): try: routes.remove(route[".id"]) except Exception as e: raise RuntimeError("删除路由表失败: {}".format(e)) for i in range(300): routeName = f"r{i + 1}" routeOut = f"l2tp-out{i + 1}" try: routes.add( **{ "dst-address": "0.0.0.0/0", "gateway": routeOut, "routing-table": routeName, } ) except Exception as e: raise RuntimeError(f"添加路由表失败: {e}") except Exception as e: raise RuntimeError(f"配置出口失败: {e}") def configJhScripts(conn: Api, config): """ 配置脚本 """ try: # 配置脚本 scripts = conn.path("system", "script") for script in scripts: if script["name"] == "up": with open("scripts/up.rsc", "rb") as file: upScript = str(file.read(), encoding="utf-8") scripts.update(**{".id": script[".id"], "source": upScript}) elif script["name"] == "down": with open("scripts/down.rsc", "rb") as file: downScript = str(file.read(), encoding="utf-8") scripts.update(**{".id": script[".id"], "source": downScript}) elif script["name"] == "onlinestatus": with open("scripts/onlinestatus.rsc", "rb") as file: onlineStatusScript = str(file.read(), encoding="utf-8") scripts.update( **{ ".id": script[".id"], "source": onlineStatusScript.replace( "", config["public"] ), } ) elif script["name"] == "pppoestatus": with open("scripts/pppoestatus.rsc", "rb") as file: pppoeStatusScript = str(file.read(), encoding="utf-8") scripts.update( **{ ".id": script[".id"], "source": pppoeStatusScript.replace( "", config["public"] ), } ) # todo 配置计划任务 except Exception as e: raise RuntimeError(f"配置脚本失败: {e}") def configJhLogs(conn: Api, config): """ 配置日志处理 """ try: # 添加日志过滤器 filters = conn.path("ip", "firewall", "filter") for filter in filters: if filter["comment"] == "natlog": try: filters.remove(filter[".id"]) except Exception as e: raise RuntimeError("删除过滤器失败: {}".format(e)) filters.add( **{ "chain": "forward", "action": "log", "comment": "natlog", "dst-address": "10.0.0.0/8", "protocol": "tcp", "connection-nat-state": "srcnat", "tcp-flags": "syn", } ) filters.add( **{ "chain": "forward", "action": "log", "comment": "natlog", "src-address": "10.0.0.0/8", "protocol": "udp", "dst-port": "!53", "connection-nat-state": "!srcnat", } ) # 添加日志动作 actions = conn.path("system", "logging", "action") for action in actions: if action["name"] in ["logremote", "logremoteidc"]: try: actions.remove(action[".id"]) except Exception as e: raise RuntimeError("删除日志动作失败: {}".format(e)) actions.add( **{ "name": "logremote", "target": "remote", "src-address": "0.0.0.0", "remote": "106.119.167.38", "remote-port": "5775", } ) actions.add( **{ "name": "logremoteidc", "target": "remote", "src-address": "0.0.0.0", "remote": "192.168.100.255", "remote-port": "5775", } ) # 配置日志动作 logs = conn.path("system", "logging") for log in logs: if "firewall" in log["topics"] and "info" in log["topics"]: try: logs.remove(log[".id"]) except Exception as e: raise RuntimeError("删除日志配置失败: {}".format(e)) logs.add( **{ "topics": "firewall,info", "prefix": config["code"], "action": "logremote", } ) logs.add( **{ "topics": "firewall,info", "prefix": config["code"], "action": "logremoteidc", } ) except Exception as e: raise RuntimeError(f"配置日志处理失败: {e}") def configJhDrop(conn: Api, config): """ 配置丢弃规则 """ try: domains = [ "kasut.org", "chigua41.xyz", "chigua35.info", "chigua32.life", "iufsvayufgiwlj6ok.com", "kaixr.top", "qiopqc.cn", "lsdhgsduyccnja18.com", "tongyan01.club", "nenmei37.club", "69lesbi.com", "ero-labs.cool", "soxue100.com", "24news.world", "aaa215.click", "qqqqqdfggjkgfgfhe.cc", "lovefootjob.com", "hadesex.com", ] ips = [ "23.231.144.26", "23.231.183.17", "23.231.182.57", "23.231.182.56", "154.92.94.91", "154.92.94.163", "192.250.241.167", "192.250.192.242", ] # 非法网站列表 layer7 = conn.path("ip", "firewall", "layer7-protocol") for item in layer7: if item["name"] == "illegal": try: layer7.remove(item[".id"]) except Exception as e: raise RuntimeError("删除 Layer7 规则失败: {}".format(e)) layer7.add( **{ "name": "illegal", "regexp": f"({'|'.join([re.escape(domain) for domain in domains])})[/:]?.*", } ) # 非法 IP 列表 addressLists = conn.path("ip", "firewall", "address-list") for item in addressLists: if item["list"] == "illegal": try: ips.remove(item["address"]) except Exception as e: continue for ip in ips: addressLists.add( **{ "list": "illegal", "address": ip, } ) # 添加丢弃规则 filters = conn.path("ip", "firewall", "filter") for item in filters: if item["comment"] == "drop illegal websites": try: filters.remove(item[".id"]) except Exception as e: raise RuntimeError("删除过滤器失败: {}".format(e)) elif item["comment"] == "drop illegal ips": try: filters.remove(item[".id"]) except Exception as e: raise RuntimeError("删除过滤器失败: {}".format(e)) filters.add( **{ "chain": "forward", "action": "drop", "layer7-protocol": "illegal", "comment": "drop illegal websites", } ) filters.add( **{ "chain": "forward", "action": "drop", "src-address-list": "illegal", "comment": "drop illegal ips", } ) except Exception as e: raise RuntimeError(f"配置丢弃规则失败: {e}") # ==================== # 极光配置 # ==================== def configJgAuth(conn: Api, config): """ 配置极光认证授权 """ try: l2tp = conn.path("interface", "l2tp-server", "server") l2tp.update(**{"enabled": "yes", "use-ipsec": "yes", "ipsec-secret": "1234"}) except Exception as e: raise RuntimeError(f"配置 l2tp 服务器失败: {e}") try: radius = conn.path("radius") for item in radius: radius.remove(item[".id"]) radius.add( **{ "service": "ppp", "address": "106.119.166.87", "secret": "juipwyk123...", } ) except Exception as e: raise RuntimeError(f"配置 radius 失败: {e}") def configJgOuts(conn: Api, config): """ 配置 vpn 出口负载均衡 """ try: count = 10 window = 20 # 配置 ppp try: ppps = conn.path("interface", "l2tp-client") for ppp in ppps: if ppp["name"].startswith("l2tp-out"): try: ppps.remove(ppp[".id"]) except Exception as e: raise RuntimeError("删除 PPP 失败: {}".format(e)) for i in range(1, count + 1): ppps.add( **{ "name": f"l2tp-out{i}", "connect-to": f"192.168.0.{int(config['gate']) + 1}", "user": f"byjd{config['gate']}api{(int(config['index']) - 1) * window + i}", "password": "byjd231", "disabled": "no", } ) except Exception as e: raise RuntimeError(f"配置 PPP 失败: {e}") # 配置路由 try: routes = conn.path("ip", "route") for route in routes: if str(route["routing-table"]).startswith("r"): try: routes.remove(route[".id"]) except Exception as e: raise RuntimeError("删除路由表失败: {}".format(e)) for i in range(1, count + 1): routeName = "r{}".format(i) routeOut = "l2tp-out{}".format(i) try: routes.add( **{ "dst-address": "0.0.0.0/0", "gateway": routeOut, "routing-table": routeName, } ) except Exception as e: raise RuntimeError(f"添加路由表失败: {e}") except Exception as e: raise RuntimeError(f"配置路由失败: {e}") except Exception as e: raise RuntimeError(f"配置出口失败: {e}") def configJgMixOuts(conn: Api, config): """ 配置 vpn 出口负载均衡 """ try: count = 300 # 配置 ppp try: ppps = conn.path("interface", "l2tp-client") for ppp in ppps: if ppp["name"].startswith("l2tp-out"): ppps.remove(ppp[".id"]) for i in range(1, count + 1): ppps.add( **{ "name": f"l2tp-out{i}", "connect-to": f"192.168.0.{int(config['gate']) + 1}", "user": f"byjd{config['gate']}api{(int(config['index']) - 1) * count + i}", "password": "byjd231", "disabled": "no", } ) except Exception as e: raise RuntimeError(f"配置 PPP 失败: {e}") # 配置路由 try: routes = conn.path("ip", "route") for route in routes: if str(route["routing-table"]).startswith("r"): routes.remove(route[".id"]) for i in range(1, count + 1): routeName = "r{}".format(i) routeOut = "l2tp-out{}".format(i) try: routes.add( **{ "dst-address": "0.0.0.0/0", "gateway": routeOut, "routing-table": routeName, } ) except Exception as e: raise RuntimeError(f"添加路由表失败: {e}") except Exception as e: raise RuntimeError(f"配置路由失败: {e}") except Exception as e: raise RuntimeError(f"配置出口失败: {e}") def configJgScripts(conn: Api, config): """ 配置脚本 """ try: # 配置脚本 scripts = conn.path("system", "script") for script in scripts: try: scripts.remove(script[".id"]) except Exception as e: raise RuntimeError("删除脚本失败: {}".format(e)) path = "scripts/jg" with open(f"{path}/up.rsc", "rb") as file: up = str(file.read(), encoding="utf-8") scripts.add(**{"name": "up", "source": up}) with open(f"{path}/down.rsc", "rb") as file: down = str(file.read(), encoding="utf-8") scripts.add(**{"name": "down", "source": down}) with open("scripts/jg/onlinestatus.rsc", "rb") as file: onlineStatus = str(file.read(), encoding="utf-8") onlineStatus = onlineStatus.replace("", config["public"]) scripts.add(**{"name": "onlinestatus", "source": onlineStatus}) with open(f"{path}/pppoestatus.rsc", "rb") as file: pppoeStatus = str(file.read(), encoding="utf-8") pppoeStatus = pppoeStatus.replace("", config["public"]) scripts.add(**{"name": "pppoestatus", "source": pppoeStatus}) with open(f"{path}/l2tpstatus.rsc", "rb") as file: l2tpstatus = str(file.read(), encoding="utf-8") scripts.add(**{"name": "l2tpstatus", "source": l2tpstatus}) with open(f"{path}/outtime.rsc", "rb") as file: outtime = str(file.read(), encoding="utf-8") scripts.add(**{"name": "outtime", "source": outtime}) with open(f"{path}/rmroute.rsc", "rb") as file: rmroute = str(file.read(), encoding="utf-8") scripts.add(**{"name": "rmroute", "source": rmroute}) with open(f"{path}/ros.rsc", "rb") as file: ros = str(file.read(), encoding="utf-8") scripts.add(**{"name": "ros", "source": ros}) scripts.add(**{"name": "num", "source": "0"}) scripts.add(**{"name": "addressname", "source": str(config["code"])}) # 配置计划任务 schedulers = conn.path("system", "scheduler") for scheduler in schedulers: if scheduler["name"] == "l2tpstatus": schedulers.remove(scheduler[".id"]) schedulers.add( **{ "name": "l2tpstatus", "interval": "5m", "on-event": "/system script run l2tpstatus", } ) except Exception as e: raise RuntimeError(f"配置脚本失败: {e}") def configJgLogs(conn: Api, config): """ 配置日志处理 """ try: # 添加日志过滤器 filters = conn.path("ip", "firewall", "filter") for filter in filters: if filter["comment"] == "natlog": try: filters.remove(filter[".id"]) except Exception as e: raise RuntimeError("删除过滤器失败: {}".format(e)) filters.add( **{ "chain": "forward", "action": "log", "comment": "natlog", "dst-address": "10.0.0.0/8", "protocol": "tcp", "connection-nat-state": "srcnat", "tcp-flags": "syn", } ) filters.add( **{ "chain": "forward", "action": "log", "comment": "natlog", "src-address": "10.0.0.0/8", "protocol": "udp", "dst-port": "!53", "connection-nat-state": "!srcnat", } ) # 添加日志动作 actions = conn.path("system", "logging", "action") for action in actions: if action["name"] in ["logremote", "logremoteidc"]: try: actions.remove(action[".id"]) except Exception as e: raise RuntimeError("删除日志动作失败: {}".format(e)) actions.add( **{ "name": "logremote", "target": "remote", "src-address": "0.0.0.0", "remote": "106.119.166.79", "remote-port": "5775", } ) actions.add( **{ "name": "logremoteidc", "target": "remote", "src-address": "0.0.0.0", "remote": "192.168.255.9", "remote-port": "5775", } ) # 配置日志动作 logs = conn.path("system", "logging") for log in logs: if "firewall" in log["topics"] and "info" in log["topics"]: try: logs.remove(log[".id"]) except Exception as e: raise RuntimeError("删除日志配置失败: {}".format(e)) logs.add( **{ "topics": "firewall,info", "prefix": config["code"], "action": "logremote", } ) logs.add( **{ "topics": "firewall,info", "prefix": config["code"], "action": "logremoteidc", } ) except Exception as e: raise RuntimeError(f"配置日志处理失败: {e}") # ==================== # 临时 # ==================== def temp(conn: Api, config): ppps = conn.path("interface", "l2tp-client") count = 0 for ppp in ppps: count += 1 if ppp["name"].startswith("l2tp-out") and ppp["running"] != True: break if count < 20: raise RuntimeError(f"有未运行的 PPP,count={count}") # file = open(f"outs/{config['code']}.csv", "w", encoding="utf-8") # file.write("ros,name,connect-to,user,running\n") # for ppp in ppps: # file.write("{},{},{},{},{}\n".format( # config["name"], # ppp["name"], # ppp["connect-to"], # ppp["user"], # ppp["running"], # )) # file.close()