mirror of
https://github.com/andrey271192/kaskad.git
synced 2026-09-20 13:49:56 +00:00
Initial release of Kaskad
Каскадная маршрутизация русских сайтов через свой набор RU-серверов с failover, Telegram-ботом и веб-интерфейсом. - bin/ — failover-script, route/domain helpers, ams/ru bootstrap - bot/ — Telegram-бот (Python, long-poll) - webui/ — Flask single-page dashboard - docs/ — установка, архитектура, API бота и WebUI - examples/ — шаблоны конфигов
This commit is contained in:
117
bin/ru-domains.py
Executable file
117
bin/ru-domains.py
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Управление доменами для маршрутизации через ru-туннель."""
|
||||
import json, subprocess, sys
|
||||
from pathlib import Path
|
||||
|
||||
JSON = Path("/etc/wireguard/ru-domains.json")
|
||||
ROUTES = "/usr/local/bin/ru-routes.sh"
|
||||
|
||||
def load():
|
||||
if not JSON.exists():
|
||||
JSON.write_text("{}")
|
||||
JSON.chmod(0o600)
|
||||
return json.loads(JSON.read_text())
|
||||
|
||||
def save(d):
|
||||
JSON.write_text(json.dumps(d, indent=2, ensure_ascii=False))
|
||||
JSON.chmod(0o600)
|
||||
|
||||
def resolve(dom):
|
||||
try:
|
||||
r = subprocess.run(["dig","+short","+time=3","+tries=2","A", dom],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
except Exception:
|
||||
return set()
|
||||
out = set()
|
||||
for line in r.stdout.split("\n"):
|
||||
line = line.strip()
|
||||
if line and line.count(".") == 3 and line.replace(".","").isdigit():
|
||||
out.add(line)
|
||||
return out
|
||||
|
||||
def routes_call(verb, ips):
|
||||
if not ips: return
|
||||
args = [ROUTES, verb] + [ip + "/32" for ip in ips]
|
||||
subprocess.run(args, capture_output=True)
|
||||
|
||||
def cmd_list():
|
||||
d = load()
|
||||
if not d: return "(пусто)"
|
||||
lines = []
|
||||
for dom, ips in sorted(d.items()):
|
||||
lines.append(f"{dom}: {len(ips)} IP")
|
||||
return "\n".join(lines)
|
||||
|
||||
def cmd_show(dom):
|
||||
d = load()
|
||||
if dom not in d: return f"{dom}: нет в списке"
|
||||
return f"{dom}:\n" + "\n".join(d[dom])
|
||||
|
||||
def cmd_add(domains):
|
||||
d = load()
|
||||
results = []
|
||||
for dom in domains:
|
||||
ips = resolve(dom)
|
||||
if not ips:
|
||||
results.append(f"❌ {dom}: не резолвится")
|
||||
continue
|
||||
old = set(d.get(dom, []))
|
||||
new = old | ips
|
||||
d[dom] = sorted(new)
|
||||
added = ips - old
|
||||
routes_call("add", sorted(added))
|
||||
results.append(f"✅ {dom}: {len(ips)} IP (+{len(added)} новых)")
|
||||
save(d)
|
||||
return "\n".join(results)
|
||||
|
||||
def cmd_remove(domains):
|
||||
d = load()
|
||||
results = []
|
||||
for dom in domains:
|
||||
if dom not in d:
|
||||
results.append(f"❌ {dom}: нет в списке")
|
||||
continue
|
||||
ips_to_check = set(d[dom])
|
||||
del d[dom]
|
||||
still_owned = set()
|
||||
for v in d.values(): still_owned.update(v)
|
||||
to_remove = ips_to_check - still_owned
|
||||
routes_call("remove", sorted(to_remove))
|
||||
results.append(f"✅ {dom}: убрано {len(to_remove)} IP из extra")
|
||||
save(d)
|
||||
return "\n".join(results)
|
||||
|
||||
def cmd_refresh():
|
||||
d = load()
|
||||
total_add = 0; total_rm = 0; failed = []
|
||||
for dom in list(d.keys()):
|
||||
new_ips = resolve(dom)
|
||||
if not new_ips:
|
||||
failed.append(dom); continue
|
||||
old = set(d[dom])
|
||||
added = new_ips - old
|
||||
removed = old - new_ips
|
||||
d[dom] = sorted(new_ips)
|
||||
# после обновления — пересобрать карту владельцев
|
||||
owners = set()
|
||||
for v in d.values(): owners.update(v)
|
||||
to_rm = sorted(removed - owners)
|
||||
routes_call("add", sorted(added))
|
||||
routes_call("remove", to_rm)
|
||||
total_add += len(added)
|
||||
total_rm += len(to_rm)
|
||||
save(d)
|
||||
msg = f"обновлено: +{total_add} / -{total_rm} IP"
|
||||
if failed: msg += f"\nне резолвятся: {', '.join(failed)}"
|
||||
return msg
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: ru-domains {list|show DOM|add DOM...|remove DOM...|refresh}"); sys.exit(1)
|
||||
cmd = sys.argv[1]; args = sys.argv[2:]
|
||||
if cmd == "list": print(cmd_list())
|
||||
elif cmd == "show": print(cmd_show(args[0]) if args else "show DOM")
|
||||
elif cmd == "add": print(cmd_add(args))
|
||||
elif cmd in ("remove","del"): print(cmd_remove(args))
|
||||
elif cmd == "refresh": print(cmd_refresh())
|
||||
else: print(f"unknown: {cmd}"); sys.exit(1)
|
||||
Reference in New Issue
Block a user