|
|
@@ -891,35 +891,38 @@ def api_cluster_adblock():
|
|
|
subprocess.run(["systemctl", "restart", config.BIND_SERVICE])
|
|
|
return jsonify({"status": "success", "message": "RPZ synced on slave."})
|
|
|
|
|
|
-# --- ΠΡΟΣΘΗΚΗ SLAVE ZONE ΜΕ ΣΩΣΤΑ IPs ---
|
|
|
+# Στο app.py του SLAVE
|
|
|
@app.route('/api/v1/cluster/zone', methods=['POST'])
|
|
|
@api_required
|
|
|
def api_add_slave():
|
|
|
+ # force=True για να διαβάσει το JSON ακόμα κι αν το content-type λείπει
|
|
|
data = request.get_json(force=True, silent=True) or {}
|
|
|
- if not data or 'domain' not in data:
|
|
|
- return jsonify({"status": "error", "message": "Missing parameters"}), 400
|
|
|
-
|
|
|
- domain = re.sub(r'[^a-zA-Z0-9\.\-\/]', '', data['domain']).replace('../', '')
|
|
|
+ domain = data.get('domain')
|
|
|
+ if not domain:
|
|
|
+ return jsonify({"status": "error", "message": "No domain provided"}), 400
|
|
|
+
|
|
|
+ # Καθαρισμός domain
|
|
|
+ domain = re.sub(r'[^a-zA-Z0-9\.\-\/]', '', domain).replace('../', '')
|
|
|
|
|
|
- if data.get('masters'):
|
|
|
- masters_list = data['masters']
|
|
|
- else:
|
|
|
+ # Λήψη των Masters (είτε από το payload είτε από την IP του Master)
|
|
|
+ masters_list = data.get('masters', [])
|
|
|
+ if not masters_list:
|
|
|
master_ip = request.headers.get('X-Forwarded-For', request.remote_addr).split(',')[0].strip()
|
|
|
masters_list = [master_ip]
|
|
|
|
|
|
masters_string = "".join([f" {ip};" for ip in masters_list])
|
|
|
-
|
|
|
+
|
|
|
conf = fm.read_file(config.LOCAL_CONF)
|
|
|
- if f'zone "{domain}"' in conf:
|
|
|
- return jsonify({"status": "error", "message": "Zone already exists"}), 409
|
|
|
+ # Αν υπάρχει ήδη, δεν την ξαναφτιάχνουμε
|
|
|
+ if f'zone "{domain}"' in conf:
|
|
|
+ return jsonify({"status": "success", "message": "Already exists"}), 200
|
|
|
|
|
|
path = os.path.join(config.CACHE_PATH, f"db.{domain}")
|
|
|
- conf += f'\nzone "{domain}" {{\n type slave;\n file "{path}";\n masters {{{masters_string} }};\n masterfile-format text;\n}};\n'
|
|
|
+ new_zone = f'\nzone "{domain}" {{\n type slave;\n file "{path}";\n masters {{{masters_string} }};\n masterfile-format text;\n}};\n'
|
|
|
|
|
|
- fm.write_file(config.LOCAL_CONF, conf)
|
|
|
+ fm.write_file(config.LOCAL_CONF, conf + new_zone)
|
|
|
subprocess.run(["rndc", "reconfig"])
|
|
|
- fm.log_audit("API_SYNC", domain, f"Auto-created Slave (Masters: {masters_string})")
|
|
|
- return jsonify({"status": "success", "message": f"Zone synced."})
|
|
|
+ return jsonify({"status": "success", "message": f"Zone {domain} added"})
|
|
|
|
|
|
@app.route('/api/v1/cluster/zone/<domain>', methods=['DELETE'])
|
|
|
@api_required
|
|
|
@@ -1020,27 +1023,33 @@ def cluster_node_service():
|
|
|
except Exception as e:
|
|
|
return jsonify({"status": "error", "message": f"Connection failed: {str(e)}"})
|
|
|
|
|
|
-# --- GLOBAL CLUSTER SYNC (MASTER ACTION) ---
|
|
|
+# Στο app.py του MASTER
|
|
|
@app.route('/api/cluster/sync_all', methods=['POST'])
|
|
|
@admin_required
|
|
|
def sync_all_cluster():
|
|
|
conf = fm.read_file(config.LOCAL_CONF)
|
|
|
- # Βρίσκουμε όλα τα domains που είναι "type master"
|
|
|
- zones = re.findall(r'zone\s+"([^"]+)"\s*\{.*?type\s+master;', conf, re.DOTALL)
|
|
|
- # Εξαιρούμε το RPZ, θα συγχρονιστεί από το AdBlock μενού
|
|
|
- zones = [z for z in zones if z != "rpz.blacklist"]
|
|
|
+ # Βρίσκουμε ΟΛΑ τα zone names που είναι μέσα σε εισαγωγικά
|
|
|
+ import re
|
|
|
+ zones = re.findall(r'zone\s+"([^"]+)"', conf)
|
|
|
|
|
|
- if not zones:
|
|
|
- return jsonify({"status": "error", "message": "No Master zones found to sync."})
|
|
|
+ # Λίστα προς αγνόηση (τα default του BIND)
|
|
|
+ ignore = ["rpz.blacklist", ".", "localhost", "127.in-addr.arpa", "0.in-addr.arpa", "255.in-addr.arpa"]
|
|
|
+ valid_zones = [z for z in zones if z not in ignore]
|
|
|
+
|
|
|
+ if not valid_zones:
|
|
|
+ return jsonify({"status": "error", "message": "No zones found in named.conf.local"})
|
|
|
|
|
|
def bulk_sync():
|
|
|
- for z in zones:
|
|
|
+ import time
|
|
|
+ for z in valid_zones:
|
|
|
+ # Εδώ καλούμε τον cluster manager να στείλει τη ζώνη
|
|
|
cm.broadcast_to_cluster('add_slave', z)
|
|
|
- time.sleep(0.5) # Μικρή καθυστέρηση για να μην "μπουκώσει" ο Slave
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
|
import threading
|
|
|
threading.Thread(target=bulk_sync, daemon=True).start()
|
|
|
- return jsonify({"status": "success", "message": f"Started pushing {len(zones)} zones to all Nodes!"})
|
|
|
+ return jsonify({"status": "success", "message": f"Pushing {len(valid_zones)} zones to nodes..."})
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
|
# Είναι σημαντικό το threaded=True για να μην κάνει "block" το UI στο self-ping
|
|
|
app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)
|