adblock_manager.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import os
  2. import re
  3. import time
  4. import datetime
  5. import subprocess
  6. import urllib.request
  7. import json
  8. import config
  9. from core.file_manager import read_file, write_file, load_adblock_lists, load_custom_rules, load_panel_settings, save_panel_settings
  10. from core.dns_manager import get_zone_block
  11. def is_valid_domain(d):
  12. if not d or len(d) > 253: return False
  13. if '..' in d or d.startswith('.'): return False
  14. # Επιτρέπει μόνο αλφαριθμητικά, παύλες και τελείες. Απορρίπτει *, |, /, ?, $ κλπ.
  15. if not re.match(r'^[a-zA-Z0-9\-_.]+$', d): return False
  16. if '.' not in d: return False
  17. return True
  18. def generate_and_apply_rpz():
  19. lists = load_adblock_lists()
  20. active_lists = [l for l in lists if l.get('enabled')]
  21. custom_rules = load_custom_rules()
  22. domains_set = set()
  23. try:
  24. # 1. Fetch Lists
  25. for lst in active_lists:
  26. req = urllib.request.Request(lst['url'], headers={'User-Agent': 'Mozilla/5.0'})
  27. try:
  28. with urllib.request.urlopen(req, timeout=15, context=config.ssl_ctx) as response:
  29. lines = response.read().decode('utf-8', errors='ignore').splitlines()
  30. for line in lines:
  31. l = line.strip()
  32. # Αγνοούμε σχόλια και άκυρες γραμμές
  33. if not l or l.startswith(('#', '!', ':', '[', '@')): continue
  34. # Αγνοούμε URL paths (π.χ. example.com/ad.gif)
  35. if '/' in l: continue
  36. d = ""
  37. if l.startswith('||'):
  38. d = re.split(r'[\^/\$:]', l[2:])[0]
  39. elif l.startswith(('0.0.0.0 ', '127.0.0.1 ')):
  40. parts = l.split()
  41. if len(parts) >= 2 and parts[1] not in ('localhost', 'broadcasthost', 'localhost.localdomain'):
  42. d = parts[1]
  43. elif ' ' not in l:
  44. d = re.split(r'[\^/\$:]', l)[0]
  45. d = d.strip().rstrip('.')
  46. # Strict Validation
  47. if is_valid_domain(d):
  48. domains_set.add(d)
  49. except Exception as e:
  50. print(f"Failed to fetch {lst['name']}: {e}")
  51. # 2. Add Custom Deny
  52. for d in custom_rules['deny']:
  53. clean_d = d.strip().rstrip('.')
  54. if clean_d.startswith('*.'): clean_d = clean_d[2:]
  55. if is_valid_domain(clean_d):
  56. domains_set.add(clean_d)
  57. # 3. Create RPZ
  58. rpz_records = []
  59. # ΠΡΩΤΑ τα Allowed (PASSTHRU)
  60. for d in custom_rules['allowed']:
  61. clean_d = d.strip().rstrip('.')
  62. if clean_d.startswith('*.'): clean_d = clean_d[2:]
  63. if is_valid_domain(clean_d):
  64. rpz_records.append(f"{clean_d}\tCNAME\trpz-passthru.")
  65. rpz_records.append(f"*.{clean_d}\tCNAME\trpz-passthru.")
  66. # ΜΕΤΑ τα Blocked
  67. for d in domains_set:
  68. if d in custom_rules['allowed'] or f"*.{d}" in custom_rules['allowed']:
  69. continue
  70. rpz_records.append(f"{d}\tCNAME\t.")
  71. rpz_records.append(f"*.{d}\tCNAME\t.")
  72. serial = time.strftime('%Y%m%d01')
  73. header = f"$TTL 60\n$ORIGIN rpz.blacklist.\n@ IN SOA localhost. root.localhost. ({serial} 3h 1h 1w 1h)\n IN NS localhost.\n"
  74. content = header + "\n".join(rpz_records) + "\n"
  75. write_file(config.ADBLOCK_DB_PATH, content)
  76. subprocess.run(["chown", "bind:bind", config.ADBLOCK_DB_PATH])
  77. # Ενημέρωση named.conf.local
  78. conf_local = read_file(config.LOCAL_CONF)
  79. if 'zone "rpz.blacklist"' not in conf_local:
  80. conf_local += f'\nzone "rpz.blacklist" {{\n type master;\n file "{config.ADBLOCK_DB_PATH}";\n allow-query {{ any; }};\n allow-transfer {{ any; }};\n}};\n'
  81. write_file(config.LOCAL_CONF, conf_local)
  82. # Ενημέρωση named.conf.options
  83. options = read_file(config.OPTIONS_FILE)
  84. if "response-policy" not in options:
  85. options = re.sub(r'(options\s*\{)', r'\1\n response-policy { zone "rpz.blacklist"; };', options)
  86. write_file(config.OPTIONS_FILE, options)
  87. subprocess.run(["rndc", "reconfig"])
  88. subprocess.run(["rndc", "reload", "rpz.blacklist"])
  89. s = load_panel_settings()
  90. s['adblock_last_update'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  91. s['adblock_domains_count'] = len(domains_set)
  92. save_panel_settings(s)
  93. return {"status": "success", "count": len(domains_set), "time": s['adblock_last_update']}
  94. except Exception as e:
  95. return {"status": "error", "message": str(e)}
  96. def disable_rpz():
  97. conf_local = read_file(config.LOCAL_CONF)
  98. options = read_file(config.OPTIONS_FILE)
  99. block = get_zone_block(conf_local, "rpz.blacklist")
  100. if block:
  101. conf_local = conf_local.replace(block, "")
  102. write_file(config.LOCAL_CONF, conf_local)
  103. options = re.sub(r'\s*response-policy\s*\{\s*zone\s*"rpz\.blacklist";\s*\};\s*', '\n', options)
  104. write_file(config.OPTIONS_FILE, options)
  105. subprocess.run(["rndc", "reconfig"])
  106. return {"status": "success", "message": "AdBlock (RPZ) disabled."}