Ajustes gerais

This commit is contained in:
2025-12-08 07:22:44 -03:00
parent c0681ea6a9
commit 7e529c8460
10 changed files with 630 additions and 111 deletions

View File

@@ -3,17 +3,17 @@ import sys
import time
import json
import uuid
import socket
import pwd
import grp
import requests
import logging
from datetime import datetime
# Configuration
CONFIG_FILE = '/opt/dnsblock/config.json'
import logging
from logging.handlers import RotatingFileHandler
# Configuration
CONFIG_FILE = '/opt/dnsblock/config.json'
STATE_FILE = '/opt/dnsblock/rpz_state.json'
LOG_DIR = '/opt/dnsblock/logs'
LOG_FILE = os.path.join(LOG_DIR, 'agent.log')
RPZ_FILE_DEFAULT = '/opt/dnsblock/rpz.dnsblock.zone'
@@ -66,32 +66,142 @@ def load_config():
logging.error(f"Error loading config: {e}")
sys.exit(1)
def generate_rpz(domains, output_file):
"""Generates the RPZ zone file."""
def get_system_domain():
"""Detects the system domain from FQDN or hostname."""
try:
fqdn = socket.getfqdn()
if fqdn and '.' in fqdn:
# Extract domain portion (e.g., server.gtecnet.com.br -> gtecnet.com.br)
parts = fqdn.split('.')
if len(parts) >= 2:
domain = '.'.join(parts[1:])
logging.info(f"Detected system domain: {domain}")
return domain
# Try hostname as fallback
hostname = socket.gethostname()
if hostname and '.' in hostname:
parts = hostname.split('.')
if len(parts) >= 2:
domain = '.'.join(parts[1:])
logging.info(f"Detected system domain from hostname: {domain}")
return domain
logging.info("Could not detect system domain, using localhost")
return "localhost"
except Exception as e:
logging.warning(f"Error detecting system domain: {e}, using localhost")
return "localhost"
def load_rpz_state():
"""Loads RPZ state from JSON file."""
if not os.path.exists(STATE_FILE):
return {'last_serial': None, 'last_date': None}
try:
with open(STATE_FILE, 'r') as f:
return json.load(f)
except Exception as e:
logging.warning(f"Error loading RPZ state: {e}")
return {'last_serial': None, 'last_date': None}
def save_rpz_state(state):
"""Saves RPZ state to JSON file."""
try:
with open(STATE_FILE, 'w') as f:
json.dump(state, f)
except Exception as e:
logging.error(f"Error saving RPZ state: {e}")
def generate_serial():
"""Generates serial in YYYYMMDDNN format."""
today = datetime.now().strftime('%Y%m%d')
state = load_rpz_state()
last_serial = state.get('last_serial')
last_date = state.get('last_date')
if last_date == today and last_serial:
# Same day, increment sequence
sequence = int(str(last_serial)[-2:]) + 1
if sequence > 99:
sequence = 99 # Cap at 99
else:
# New day, reset sequence
sequence = 0
new_serial = int(f"{today}{sequence:02d}")
# Save state
save_rpz_state({'last_serial': new_serial, 'last_date': today})
return new_serial
def apply_file_ownership(path, file_owner):
"""Apply user:group ownership to a file or directory."""
if not file_owner:
return True
try:
parts = file_owner.split(':')
user = parts[0]
group = parts[1] if len(parts) > 1 else user
uid = pwd.getpwnam(user).pw_uid
gid = grp.getgrnam(group).gr_gid
os.chown(path, uid, gid)
logging.debug(f"Applied ownership {file_owner} to {path}")
return True
except KeyError as e:
logging.warning(f"User or group not found for file_owner '{file_owner}': {e}")
return False
except PermissionError as e:
logging.warning(f"Permission denied setting ownership on {path}: {e}")
return False
except Exception as e:
logging.error(f"Error applying ownership to {path}: {e}")
return False
def generate_rpz(domains, output_file, file_owner=None):
"""Generates the RPZ zone file with proper SOA header."""
try:
# Ensure directory exists
os.makedirs(os.path.dirname(output_file), exist_ok=True)
output_dir = os.path.dirname(output_file)
if output_dir:
os.makedirs(output_dir, exist_ok=True)
# Apply ownership to directory
if file_owner:
apply_file_ownership(output_dir, file_owner)
# Get system domain and generate serial
system_domain = get_system_domain()
serial = generate_serial()
with open(output_file, 'w') as f:
f.write("$TTL 30\n")
f.write("@ IN SOA rpz.dnsblock.zone. root.rpz.dnsblock.zone. (\n")
f.write(f" {int(time.time())} ; Serial\n")
f.write(" 30 ; Refresh\n")
f.write(" 15 ; Retry\n")
f.write(" 604800 ; Expire\n")
f.write(" 30 ) ; Negative Cache TTL\n")
f.write(";\n")
f.write("@ IN NS localhost.\n")
f.write("@ IN A 127.0.0.1\n")
f.write(";\n")
f.write("; Blocked Domains\n")
f.write("$TTL 1H\n")
f.write(f"@ IN SOA localhost. {system_domain}. (\n")
f.write(f" {serial} ; Serial\n")
f.write(" 1h ; Refresh\n")
f.write(" 15m ; Retry\n")
f.write(" 30d ; Expire\n")
f.write(" 2h ; Negative Cache TTL\n")
f.write(" )\n")
f.write(f" NS {system_domain}.\n")
f.write("\n")
f.write("; RPZ block hosts\n")
f.write("\n")
for domain in domains:
# CNAME to . (NXDOMAIN) or specific sinkhole
f.write(f"{domain} CNAME .\n")
f.write(f"*.{domain} CNAME .\n")
logging.info(f"RPZ file generated at {output_file} with {len(domains)} domains.")
# Apply ownership to file
if file_owner:
apply_file_ownership(output_file, file_owner)
logging.info(f"RPZ file generated at {output_file} with {len(domains)} domains (serial: {serial}).")
return True
except Exception as e:
logging.error(f"Error generating RPZ: {e}")
@@ -106,6 +216,7 @@ def main():
api_url = config.get('api_url')
rpz_file = config.get('rpz_file', RPZ_FILE_DEFAULT)
reload_command = config.get('reload_command')
file_owner = config.get('file_owner') # Ex: 'unbound:unbound'
if not serial_key or not api_url:
logging.error("Missing serial_key or api_url in config.")
@@ -140,7 +251,7 @@ def main():
if current_checksum != last_checksum:
logging.info("Change detected in domain list. Updating RPZ...")
domains = data.get('domains', [])
if generate_rpz(domains, rpz_file):
if generate_rpz(domains, rpz_file, file_owner):
last_checksum = current_checksum
if reload_command: