Ajustes gerais
This commit is contained in:
Binary file not shown.
@@ -115,8 +115,6 @@
|
||||
('calendar', '/usr/lib/python3.11/calendar.py', 'PYMODULE'),
|
||||
('urllib.parse', '/usr/lib/python3.11/urllib/parse.py', 'PYMODULE'),
|
||||
('ipaddress', '/usr/lib/python3.11/ipaddress.py', 'PYMODULE'),
|
||||
('socket', '/usr/lib/python3.11/socket.py', 'PYMODULE'),
|
||||
('selectors', '/usr/lib/python3.11/selectors.py', 'PYMODULE'),
|
||||
('quopri', '/usr/lib/python3.11/quopri.py', 'PYMODULE'),
|
||||
('email', '/usr/lib/python3.11/email/__init__.py', 'PYMODULE'),
|
||||
('email.parser', '/usr/lib/python3.11/email/parser.py', 'PYMODULE'),
|
||||
@@ -149,12 +147,12 @@
|
||||
('opcode', '/usr/lib/python3.11/opcode.py', 'PYMODULE'),
|
||||
('ast', '/usr/lib/python3.11/ast.py', 'PYMODULE'),
|
||||
('stringprep', '/usr/lib/python3.11/stringprep.py', 'PYMODULE'),
|
||||
('_py_abc', '/usr/lib/python3.11/_py_abc.py', 'PYMODULE'),
|
||||
('tracemalloc', '/usr/lib/python3.11/tracemalloc.py', 'PYMODULE'),
|
||||
('pickle', '/usr/lib/python3.11/pickle.py', 'PYMODULE'),
|
||||
('pprint', '/usr/lib/python3.11/pprint.py', 'PYMODULE'),
|
||||
('dataclasses', '/usr/lib/python3.11/dataclasses.py', 'PYMODULE'),
|
||||
('_compat_pickle', '/usr/lib/python3.11/_compat_pickle.py', 'PYMODULE'),
|
||||
('_py_abc', '/usr/lib/python3.11/_py_abc.py', 'PYMODULE'),
|
||||
('logging.handlers', '/usr/lib/python3.11/logging/handlers.py', 'PYMODULE'),
|
||||
('http.client', '/usr/lib/python3.11/http/client.py', 'PYMODULE'),
|
||||
('ssl', '/usr/lib/python3.11/ssl.py', 'PYMODULE'),
|
||||
@@ -384,6 +382,8 @@
|
||||
('urllib3.contrib.emscripten.fetch',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/urllib3/contrib/emscripten/fetch.py',
|
||||
'PYMODULE'),
|
||||
('socket', '/usr/lib/python3.11/socket.py', 'PYMODULE'),
|
||||
('selectors', '/usr/lib/python3.11/selectors.py', 'PYMODULE'),
|
||||
('uuid', '/usr/lib/python3.11/uuid.py', 'PYMODULE'),
|
||||
('subprocess', '/usr/lib/python3.11/subprocess.py', 'PYMODULE'),
|
||||
('signal', '/usr/lib/python3.11/signal.py', 'PYMODULE'),
|
||||
@@ -467,25 +467,17 @@
|
||||
('libuuid.so.1', '/lib/x86_64-linux-gnu/libuuid.so.1', 'BINARY')],
|
||||
[],
|
||||
[],
|
||||
[('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('certifi/cacert.pem',
|
||||
[('certifi/cacert.pem',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/cacert.pem',
|
||||
'DATA'),
|
||||
('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build/dnsblock-agent/base_library.zip',
|
||||
'DATA')],
|
||||
[('sre_compile', '/usr/lib/python3.11/sre_compile.py', 'PYMODULE'),
|
||||
('traceback', '/usr/lib/python3.11/traceback.py', 'PYMODULE'),
|
||||
('_weakrefset', '/usr/lib/python3.11/_weakrefset.py', 'PYMODULE'),
|
||||
('enum', '/usr/lib/python3.11/enum.py', 'PYMODULE'),
|
||||
('keyword', '/usr/lib/python3.11/keyword.py', 'PYMODULE'),
|
||||
('stat', '/usr/lib/python3.11/stat.py', 'PYMODULE'),
|
||||
('sre_parse', '/usr/lib/python3.11/sre_parse.py', 'PYMODULE'),
|
||||
('weakref', '/usr/lib/python3.11/weakref.py', 'PYMODULE'),
|
||||
('linecache', '/usr/lib/python3.11/linecache.py', 'PYMODULE'),
|
||||
('functools', '/usr/lib/python3.11/functools.py', 'PYMODULE'),
|
||||
[('copyreg', '/usr/lib/python3.11/copyreg.py', 'PYMODULE'),
|
||||
('genericpath', '/usr/lib/python3.11/genericpath.py', 'PYMODULE'),
|
||||
('encodings.zlib_codec',
|
||||
'/usr/lib/python3.11/encodings/zlib_codec.py',
|
||||
'PYMODULE'),
|
||||
@@ -716,26 +708,34 @@
|
||||
('encodings.ascii', '/usr/lib/python3.11/encodings/ascii.py', 'PYMODULE'),
|
||||
('encodings.aliases', '/usr/lib/python3.11/encodings/aliases.py', 'PYMODULE'),
|
||||
('encodings', '/usr/lib/python3.11/encodings/__init__.py', 'PYMODULE'),
|
||||
('abc', '/usr/lib/python3.11/abc.py', 'PYMODULE'),
|
||||
('locale', '/usr/lib/python3.11/locale.py', 'PYMODULE'),
|
||||
('ntpath', '/usr/lib/python3.11/ntpath.py', 'PYMODULE'),
|
||||
('io', '/usr/lib/python3.11/io.py', 'PYMODULE'),
|
||||
('reprlib', '/usr/lib/python3.11/reprlib.py', 'PYMODULE'),
|
||||
('heapq', '/usr/lib/python3.11/heapq.py', 'PYMODULE'),
|
||||
('sre_constants', '/usr/lib/python3.11/sre_constants.py', 'PYMODULE'),
|
||||
('collections.abc', '/usr/lib/python3.11/collections/abc.py', 'PYMODULE'),
|
||||
('collections', '/usr/lib/python3.11/collections/__init__.py', 'PYMODULE'),
|
||||
('posixpath', '/usr/lib/python3.11/posixpath.py', 'PYMODULE'),
|
||||
('_collections_abc', '/usr/lib/python3.11/_collections_abc.py', 'PYMODULE'),
|
||||
('codecs', '/usr/lib/python3.11/codecs.py', 'PYMODULE'),
|
||||
('traceback', '/usr/lib/python3.11/traceback.py', 'PYMODULE'),
|
||||
('types', '/usr/lib/python3.11/types.py', 'PYMODULE'),
|
||||
('warnings', '/usr/lib/python3.11/warnings.py', 'PYMODULE'),
|
||||
('keyword', '/usr/lib/python3.11/keyword.py', 'PYMODULE'),
|
||||
('posixpath', '/usr/lib/python3.11/posixpath.py', 'PYMODULE'),
|
||||
('_weakrefset', '/usr/lib/python3.11/_weakrefset.py', 'PYMODULE'),
|
||||
('stat', '/usr/lib/python3.11/stat.py', 'PYMODULE'),
|
||||
('sre_compile', '/usr/lib/python3.11/sre_compile.py', 'PYMODULE'),
|
||||
('sre_constants', '/usr/lib/python3.11/sre_constants.py', 'PYMODULE'),
|
||||
('heapq', '/usr/lib/python3.11/heapq.py', 'PYMODULE'),
|
||||
('operator', '/usr/lib/python3.11/operator.py', 'PYMODULE'),
|
||||
('copyreg', '/usr/lib/python3.11/copyreg.py', 'PYMODULE'),
|
||||
('re._parser', '/usr/lib/python3.11/re/_parser.py', 'PYMODULE'),
|
||||
('re._constants', '/usr/lib/python3.11/re/_constants.py', 'PYMODULE'),
|
||||
('re._compiler', '/usr/lib/python3.11/re/_compiler.py', 'PYMODULE'),
|
||||
('re._casefix', '/usr/lib/python3.11/re/_casefix.py', 'PYMODULE'),
|
||||
('re', '/usr/lib/python3.11/re/__init__.py', 'PYMODULE'),
|
||||
('genericpath', '/usr/lib/python3.11/genericpath.py', 'PYMODULE'),
|
||||
('types', '/usr/lib/python3.11/types.py', 'PYMODULE'),
|
||||
('warnings', '/usr/lib/python3.11/warnings.py', 'PYMODULE'),
|
||||
('functools', '/usr/lib/python3.11/functools.py', 'PYMODULE'),
|
||||
('sre_parse', '/usr/lib/python3.11/sre_parse.py', 'PYMODULE'),
|
||||
('weakref', '/usr/lib/python3.11/weakref.py', 'PYMODULE'),
|
||||
('collections.abc', '/usr/lib/python3.11/collections/abc.py', 'PYMODULE'),
|
||||
('collections', '/usr/lib/python3.11/collections/__init__.py', 'PYMODULE'),
|
||||
('locale', '/usr/lib/python3.11/locale.py', 'PYMODULE'),
|
||||
('enum', '/usr/lib/python3.11/enum.py', 'PYMODULE'),
|
||||
('io', '/usr/lib/python3.11/io.py', 'PYMODULE'),
|
||||
('codecs', '/usr/lib/python3.11/codecs.py', 'PYMODULE'),
|
||||
('ntpath', '/usr/lib/python3.11/ntpath.py', 'PYMODULE'),
|
||||
('abc', '/usr/lib/python3.11/abc.py', 'PYMODULE'),
|
||||
('reprlib', '/usr/lib/python3.11/reprlib.py', 'PYMODULE'),
|
||||
('linecache', '/usr/lib/python3.11/linecache.py', 'PYMODULE'),
|
||||
('os', '/usr/lib/python3.11/os.py', 'PYMODULE')])
|
||||
|
||||
@@ -109,19 +109,19 @@
|
||||
('libbz2.so.1.0', '/lib/x86_64-linux-gnu/libbz2.so.1.0', 'BINARY'),
|
||||
('libssl.so.3', '/lib/x86_64-linux-gnu/libssl.so.3', 'BINARY'),
|
||||
('libuuid.so.1', '/lib/x86_64-linux-gnu/libuuid.so.1', 'BINARY'),
|
||||
('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('certifi/cacert.pem',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/cacert.pem',
|
||||
'DATA'),
|
||||
('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build/dnsblock-agent/base_library.zip',
|
||||
'DATA')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1765065952,
|
||||
1765128812,
|
||||
[('run',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run',
|
||||
'EXECUTABLE')],
|
||||
|
||||
@@ -104,12 +104,12 @@
|
||||
('libbz2.so.1.0', '/lib/x86_64-linux-gnu/libbz2.so.1.0', 'BINARY'),
|
||||
('libssl.so.3', '/lib/x86_64-linux-gnu/libssl.so.3', 'BINARY'),
|
||||
('libuuid.so.1', '/lib/x86_64-linux-gnu/libuuid.so.1', 'BINARY'),
|
||||
('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('certifi/cacert.pem',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/cacert.pem',
|
||||
'DATA'),
|
||||
('certifi/py.typed',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build_venv/lib/python3.11/site-packages/certifi/py.typed',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'/home/halbebruno/Projetos/DNSBlock/agent/build/dnsblock-agent/base_library.zip',
|
||||
'DATA')],
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -151,6 +151,7 @@ imports:
|
||||
• <a href="#enum">enum</a>
|
||||
• <a href="#functools">functools</a>
|
||||
• <a href="#genericpath">genericpath</a>
|
||||
• <a href="#grp">grp</a>
|
||||
• <a href="#heapq">heapq</a>
|
||||
• <a href="#io">io</a>
|
||||
• <a href="#json">json</a>
|
||||
@@ -163,6 +164,7 @@ imports:
|
||||
• <a href="#operator">operator</a>
|
||||
• <a href="#os">os</a>
|
||||
• <a href="#posixpath">posixpath</a>
|
||||
• <a href="#pwd">pwd</a>
|
||||
• <a href="#pyi_rth_inspect.py">pyi_rth_inspect.py</a>
|
||||
• <a href="#re">re</a>
|
||||
• <a href="#re._casefix">re._casefix</a>
|
||||
@@ -171,6 +173,7 @@ imports:
|
||||
• <a href="#re._parser">re._parser</a>
|
||||
• <a href="#reprlib">reprlib</a>
|
||||
• <a href="#requests">requests</a>
|
||||
• <a href="#socket">socket</a>
|
||||
• <a href="#sre_compile">sre_compile</a>
|
||||
• <a href="#sre_constants">sre_constants</a>
|
||||
• <a href="#sre_parse">sre_parse</a>
|
||||
@@ -5517,7 +5520,8 @@ imported by:
|
||||
<a name="grp"></a>
|
||||
<tt>grp</tt> <span class="moduletype"><i>(builtin module)</i></span> <div class="import">
|
||||
imported by:
|
||||
<a href="#pathlib">pathlib</a>
|
||||
<a href="#main.py">main.py</a>
|
||||
• <a href="#pathlib">pathlib</a>
|
||||
• <a href="#shutil">shutil</a>
|
||||
• <a href="#subprocess">subprocess</a>
|
||||
• <a href="#tarfile">tarfile</a>
|
||||
@@ -7274,6 +7278,7 @@ imported by:
|
||||
<tt>pwd</tt> <span class="moduletype"><i>(builtin module)</i></span> <div class="import">
|
||||
imported by:
|
||||
<a href="#getpass">getpass</a>
|
||||
• <a href="#main.py">main.py</a>
|
||||
• <a href="#netrc">netrc</a>
|
||||
• <a href="#pathlib">pathlib</a>
|
||||
• <a href="#posixpath">posixpath</a>
|
||||
@@ -8230,6 +8235,7 @@ imported by:
|
||||
• <a href="#ftplib">ftplib</a>
|
||||
• <a href="#http.client">http.client</a>
|
||||
• <a href="#logging.handlers">logging.handlers</a>
|
||||
• <a href="#main.py">main.py</a>
|
||||
• <a href="#platform">platform</a>
|
||||
• <a href="#requests.adapters">requests.adapters</a>
|
||||
• <a href="#requests.utils">requests.utils</a>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"serial_key": "YOUR_SERIAL_KEY_HERE",
|
||||
"serial_key": "SUA_CHAVE_SERIAL_AQUI",
|
||||
"api_url": "https://app.dnsblock.com.br",
|
||||
"rpz_file": "/etc/unbound/rpz.zones/rpz.dnsblock.zone",
|
||||
"reload_command": "systemctl reload unbound"
|
||||
"rpz_file": "/opt/dnsblock/rpz/rpz.dnsblock.zone",
|
||||
"reload_command": "systemctl reload unbound",
|
||||
"file_owner": "unbound:unbound"
|
||||
}
|
||||
|
||||
153
agent/main.py
153
agent/main.py
@@ -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:
|
||||
|
||||
@@ -1,58 +1,459 @@
|
||||
#!/bin/bash
|
||||
|
||||
# DNSBlock Agent Installer (Binary Distribution)
|
||||
# ============================================================================
|
||||
# DNSBlock Agent - Script de Instalação e Desinstalação
|
||||
# ============================================================================
|
||||
# Este script realiza a instalação ou desinstalação completa do DNSBlock Agent
|
||||
# Requer privilégios de root para execução
|
||||
#
|
||||
# Uso:
|
||||
# ./install.sh Instalação interativa
|
||||
# ./install.sh uninstall Desinstalação
|
||||
# ============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# Diretórios e arquivos
|
||||
INSTALL_DIR="/opt/dnsblock"
|
||||
SOURCE_DIR=$(pwd)
|
||||
RPZ_DIR="$INSTALL_DIR/rpz"
|
||||
SERVICE_FILE="/etc/systemd/system/dnsblock-agent.service"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Check root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
# Configurações do Unbound
|
||||
UNBOUND_CONF_DIR="/etc/unbound/unbound.conf.d"
|
||||
UNBOUND_MAIN_CONF="/etc/unbound/unbound.conf"
|
||||
DNSBLOCK_CONF="$UNBOUND_CONF_DIR/dnsblock.conf"
|
||||
DNSBLOCK_INCLUDE='include: "/etc/unbound/unbound.conf.d/dnsblock.conf"'
|
||||
|
||||
# Variáveis globais
|
||||
SERIAL=""
|
||||
NO_SERIAL=false
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÕES UTILITÁRIAS
|
||||
# ============================================================================
|
||||
|
||||
# Verificar se está executando como root
|
||||
verificar_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
whiptail --title "Erro" --msgbox "Este script deve ser executado como root.\n\nExecute novamente com sudo." 10 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing DNSBlock Agent..."
|
||||
|
||||
# Create Directory
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
|
||||
# Copy Binary
|
||||
if [ -f "$SOURCE_DIR/dnsblock-agent" ]; then
|
||||
cp "$SOURCE_DIR/dnsblock-agent" "$INSTALL_DIR/"
|
||||
chmod +x "$INSTALL_DIR/dnsblock-agent"
|
||||
else
|
||||
echo "Error: dnsblock-agent binary not found in current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create Config if not exists
|
||||
if [ ! -f "$INSTALL_DIR/config.json" ]; then
|
||||
echo "Creating default config..."
|
||||
if [ -f "$SOURCE_DIR/config.json.example" ]; then
|
||||
cp "$SOURCE_DIR/config.json.example" "$INSTALL_DIR/config.json"
|
||||
else
|
||||
cat <<EOF > "$INSTALL_DIR/config.json"
|
||||
{
|
||||
"serial_key": "YOUR_SERIAL_KEY_HERE",
|
||||
"api_url": "https://seu-painel.com",
|
||||
"rpz_file": "/opt/dnsblock/rpz.dnsblock.zone"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
echo "Config file created at $INSTALL_DIR/config.json. Please edit it with your Serial Key and API URL."
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup Systemd Service
|
||||
echo "Setting up systemd service..."
|
||||
if [ -f "$SOURCE_DIR/dnsblock-agent.service" ]; then
|
||||
cp "$SOURCE_DIR/dnsblock-agent.service" /etc/systemd/system/
|
||||
# Verificar dependências
|
||||
verificar_dependencias() {
|
||||
local deps_faltando=""
|
||||
|
||||
if ! command -v whiptail &> /dev/null; then
|
||||
echo "Erro: whiptail não encontrado. Instale-o antes de continuar."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v tar &> /dev/null; then
|
||||
deps_faltando="$deps_faltando tar"
|
||||
fi
|
||||
|
||||
if ! command -v unbound-checkconf &> /dev/null; then
|
||||
deps_faltando="$deps_faltando unbound-checkconf"
|
||||
fi
|
||||
|
||||
if [ -n "$deps_faltando" ]; then
|
||||
whiptail --title "Dependências Faltando" \
|
||||
--msgbox "As seguintes dependências não foram encontradas:\n$deps_faltando\n\nPor favor, instale-as antes de continuar." 12 55
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÕES DE SERIAL
|
||||
# ============================================================================
|
||||
|
||||
# Solicitar o serial via whiptail
|
||||
solicitar_serial() {
|
||||
local serial=""
|
||||
|
||||
serial=$(whiptail --title "DNSBlock Agent - Ativação" \
|
||||
--inputbox "Digite o serial de ativação do agente:\n\n(Deixe em branco para instalar sem serial)" \
|
||||
12 60 3>&1 1>&2 2>&3)
|
||||
|
||||
local status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
# Usuário cancelou com ESC ou Cancel
|
||||
whiptail --title "Instalação Cancelada" \
|
||||
--msgbox "A instalação foi cancelada pelo usuário." 8 45
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$serial" ]; then
|
||||
# Serial em branco - perguntar se deseja continuar
|
||||
if whiptail --title "Instalação sem Serial" \
|
||||
--yesno "Você não informou um serial.\n\nDeseja instalar sem serial?\n\n(O serviço será ativado mas não inicializado)\n\nVocê pode obter seu serial em:\nhttp://painel.dnsblock.com.br" \
|
||||
14 55; then
|
||||
NO_SERIAL=true
|
||||
echo ""
|
||||
else
|
||||
whiptail --title "Instalação Cancelada" \
|
||||
--msgbox "A instalação foi cancelada pelo usuário." 8 45
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo "$serial"
|
||||
fi
|
||||
}
|
||||
|
||||
# Atualizar o serial no config.json
|
||||
atualizar_config_serial() {
|
||||
local serial="$1"
|
||||
local config_file="$INSTALL_DIR/config.json"
|
||||
|
||||
if [ -f "$config_file" ]; then
|
||||
sed -i "s/\"serial_key\":[[:space:]]*\"[^\"]*\"/\"serial_key\": \"$serial\"/" "$config_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÕES DE CONFIGURAÇÃO DO UNBOUND
|
||||
# ============================================================================
|
||||
|
||||
# Encontrar o arquivo de configuração apropriado do Unbound
|
||||
encontrar_arquivo_config_unbound() {
|
||||
local config_file=""
|
||||
|
||||
# Verificar se existe algum arquivo com configuração RPZ
|
||||
for conf in "$UNBOUND_CONF_DIR"/*.conf; do
|
||||
if [ -f "$conf" ] && grep -q "rpz:" "$conf" 2>/dev/null; then
|
||||
config_file="$conf"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Se não encontrou arquivo com RPZ, usar local.conf se existir
|
||||
if [ -z "$config_file" ]; then
|
||||
if [ -f "$UNBOUND_CONF_DIR/local.conf" ]; then
|
||||
config_file="$UNBOUND_CONF_DIR/local.conf"
|
||||
elif [ -f "$UNBOUND_MAIN_CONF" ]; then
|
||||
config_file="$UNBOUND_MAIN_CONF"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$config_file"
|
||||
}
|
||||
|
||||
# Verificar se o include já existe
|
||||
verificar_include_existente() {
|
||||
local include_pattern='include:[[:space:]]*"/etc/unbound/unbound.conf.d/dnsblock.conf"'
|
||||
|
||||
if [ -f "$UNBOUND_MAIN_CONF" ] && grep -qE "$include_pattern" "$UNBOUND_MAIN_CONF" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
for conf in "$UNBOUND_CONF_DIR"/*.conf; do
|
||||
if [ -f "$conf" ] && grep -qE "$include_pattern" "$conf" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Configurar o Unbound para usar o DNSBlock
|
||||
configurar_unbound() {
|
||||
# Criar diretório de configuração do Unbound se não existir
|
||||
if [ ! -d "$UNBOUND_CONF_DIR" ]; then
|
||||
mkdir -p "$UNBOUND_CONF_DIR"
|
||||
chown unbound:unbound "$UNBOUND_CONF_DIR"
|
||||
fi
|
||||
|
||||
# Criar o diretório RPZ
|
||||
mkdir -p "$RPZ_DIR"
|
||||
chown unbound:unbound "$RPZ_DIR"
|
||||
|
||||
# Criar arquivo de configuração do DNSBlock para o Unbound
|
||||
cat > "$DNSBLOCK_CONF" << 'EOF'
|
||||
rpz:
|
||||
name: rpz.dnsblock.zone
|
||||
zonefile: /opt/dnsblock/rpz/rpz.dnsblock.zone
|
||||
rpz-action-override: nxdomain
|
||||
EOF
|
||||
|
||||
chown unbound:unbound "$DNSBLOCK_CONF"
|
||||
chmod 644 "$DNSBLOCK_CONF"
|
||||
|
||||
# Adicionar include se não existir
|
||||
if ! verificar_include_existente; then
|
||||
local config_file=$(encontrar_arquivo_config_unbound)
|
||||
|
||||
if [ -z "$config_file" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -q "rpz:" "$config_file" 2>/dev/null; then
|
||||
sed -i "/rpz:/i # DNSBlock\n$DNSBLOCK_INCLUDE\n" "$config_file"
|
||||
else
|
||||
echo "" >> "$config_file"
|
||||
echo "# DNSBlock" >> "$config_file"
|
||||
echo "$DNSBLOCK_INCLUDE" >> "$config_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Criar arquivo RPZ vazio se não existir
|
||||
local rpz_file="$RPZ_DIR/rpz.dnsblock.zone"
|
||||
if [ ! -f "$rpz_file" ]; then
|
||||
cat > "$rpz_file" << 'EOF'
|
||||
$TTL 1H
|
||||
@ SOA localhost. hostmaster.localhost. (
|
||||
1 ; Serial
|
||||
1h ; Refresh
|
||||
15m ; Retry
|
||||
30d ; Expire
|
||||
2h ; Negative Cache TTL
|
||||
)
|
||||
NS localhost.
|
||||
; RPZ block hosts
|
||||
EOF
|
||||
chown unbound:unbound "$rpz_file"
|
||||
chmod 644 "$rpz_file"
|
||||
fi
|
||||
|
||||
# Verificar configuração do Unbound
|
||||
if ! unbound-checkconf &>/dev/null; then
|
||||
rm -f "$DNSBLOCK_CONF"
|
||||
remover_include_unbound
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Reiniciar o Unbound
|
||||
systemctl restart unbound 2>/dev/null || true
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Remover o include do DNSBlock dos arquivos de configuração
|
||||
remover_include_unbound() {
|
||||
local include_pattern='include:[[:space:]]*"/etc/unbound/unbound.conf.d/dnsblock.conf"'
|
||||
local comment_pattern='#[[:space:]]*DNSBlock'
|
||||
|
||||
if [ -f "$UNBOUND_MAIN_CONF" ]; then
|
||||
sed -i "/$include_pattern/d" "$UNBOUND_MAIN_CONF"
|
||||
sed -i "/$comment_pattern/d" "$UNBOUND_MAIN_CONF"
|
||||
fi
|
||||
|
||||
for conf in "$UNBOUND_CONF_DIR"/*.conf; do
|
||||
if [ -f "$conf" ] && [ "$conf" != "$DNSBLOCK_CONF" ]; then
|
||||
sed -i "/$include_pattern/d" "$conf"
|
||||
sed -i "/$comment_pattern/d" "$conf"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Remover configuração do Unbound
|
||||
remover_configuracao_unbound() {
|
||||
remover_include_unbound
|
||||
|
||||
if [ -f "$DNSBLOCK_CONF" ]; then
|
||||
rm -f "$DNSBLOCK_CONF"
|
||||
fi
|
||||
|
||||
if unbound-checkconf &>/dev/null; then
|
||||
systemctl restart unbound 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÃO DE INSTALAÇÃO
|
||||
# ============================================================================
|
||||
|
||||
instalar() {
|
||||
# Verificar dependências
|
||||
verificar_dependencias
|
||||
|
||||
# Verificar se já está instalado
|
||||
if [ -d "$INSTALL_DIR" ]; then
|
||||
if ! whiptail --title "DNSBlock já instalado" \
|
||||
--yesno "O DNSBlock Agent já está instalado.\n\nDeseja reinstalar?" 10 50; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parar serviço se estiver rodando
|
||||
systemctl stop dnsblock-agent 2>/dev/null || true
|
||||
systemctl disable dnsblock-agent 2>/dev/null || true
|
||||
rm -rf "$INSTALL_DIR"
|
||||
fi
|
||||
|
||||
# Solicitar serial
|
||||
SERIAL=$(solicitar_serial)
|
||||
|
||||
# Exibir progresso
|
||||
{
|
||||
echo "10"; echo "# Criando diretórios..."
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mkdir -p "$INSTALL_DIR/logs"
|
||||
mkdir -p "$INSTALL_DIR/rpz"
|
||||
sleep 0.3
|
||||
|
||||
echo "30"; echo "# Copiando arquivos..."
|
||||
# Copiar todos os arquivos exceto o service file e o próprio install.sh
|
||||
for item in "$SCRIPT_DIR"/*; do
|
||||
local basename=$(basename "$item")
|
||||
if [ "$basename" != "dnsblock-agent.service" ] && [ "$basename" != "install.sh" ]; then
|
||||
cp -r "$item" "$INSTALL_DIR/"
|
||||
fi
|
||||
done
|
||||
sleep 0.3
|
||||
|
||||
echo "50"; echo "# Configurando permissões..."
|
||||
chmod +x "$INSTALL_DIR/dnsblock-agent" 2>/dev/null || true
|
||||
touch "$INSTALL_DIR/logs/agent.log"
|
||||
chown -R unbound:unbound "$INSTALL_DIR"
|
||||
chmod 755 "$INSTALL_DIR"
|
||||
sleep 0.3
|
||||
|
||||
echo "60"; echo "# Configurando serial..."
|
||||
if [ -n "$SERIAL" ]; then
|
||||
atualizar_config_serial "$SERIAL"
|
||||
fi
|
||||
sleep 0.3
|
||||
|
||||
echo "70"; echo "# Instalando serviço..."
|
||||
if [ -f "$SCRIPT_DIR/dnsblock-agent.service" ]; then
|
||||
mv "$SCRIPT_DIR/dnsblock-agent.service" "$SERVICE_FILE"
|
||||
fi
|
||||
systemctl daemon-reload
|
||||
systemctl enable dnsblock-agent
|
||||
sleep 0.3
|
||||
|
||||
echo "Installation Complete!"
|
||||
echo "1. Edit /opt/dnsblock/config.json"
|
||||
echo "2. Start service: systemctl start dnsblock-agent"
|
||||
else
|
||||
echo "Error: dnsblock-agent.service not found."
|
||||
echo "85"; echo "# Configurando Unbound..."
|
||||
configurar_unbound || true
|
||||
sleep 0.3
|
||||
|
||||
echo "95"; echo "# Finalizando..."
|
||||
if [ -n "$SERIAL" ]; then
|
||||
systemctl start dnsblock-agent
|
||||
fi
|
||||
sleep 0.3
|
||||
|
||||
echo "100"; echo "# Concluído!"
|
||||
} | whiptail --title "DNSBlock Agent - Instalação" --gauge "Iniciando instalação..." 8 60 0
|
||||
|
||||
# Exibir mensagem final
|
||||
if [ -n "$SERIAL" ]; then
|
||||
whiptail --title "Instalação Concluída" \
|
||||
--msgbox "O DNSBlock Agent foi instalado e iniciado com sucesso!\n\nComandos úteis:\n • Status: systemctl status dnsblock-agent\n • Logs: journalctl -u dnsblock-agent -f\n • Reiniciar: systemctl restart dnsblock-agent" 14 60
|
||||
else
|
||||
whiptail --title "Instalação Concluída (sem serial)" \
|
||||
--msgbox "O DNSBlock Agent foi instalado mas NÃO foi iniciado.\n\nPara ativar o agente:\n\n1. Obtenha seu serial em:\n http://painel.dnsblock.com.br\n\n2. Edite o arquivo:\n $INSTALL_DIR/config.json\n\n3. Inicie o serviço:\n systemctl start dnsblock-agent" 18 60
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÃO DE DESINSTALAÇÃO
|
||||
# ============================================================================
|
||||
|
||||
desinstalar() {
|
||||
if [ ! -d "$INSTALL_DIR" ] && [ ! -f "$SERVICE_FILE" ] && [ ! -f "$DNSBLOCK_CONF" ]; then
|
||||
whiptail --title "Não Instalado" \
|
||||
--msgbox "O DNSBlock Agent não parece estar instalado." 8 50
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! whiptail --title "Confirmar Desinstalação" \
|
||||
--yesno "Você está prestes a desinstalar o DNSBlock Agent.\n\nTodos os arquivos e configurações serão removidos.\n\nDeseja continuar?" 12 55; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Exibir progresso
|
||||
{
|
||||
echo "10"; echo "# Parando serviço..."
|
||||
systemctl stop dnsblock-agent 2>/dev/null || true
|
||||
sleep 0.3
|
||||
|
||||
echo "30"; echo "# Desabilitando serviço..."
|
||||
systemctl disable dnsblock-agent 2>/dev/null || true
|
||||
sleep 0.3
|
||||
|
||||
echo "50"; echo "# Removendo arquivo de serviço..."
|
||||
rm -f "$SERVICE_FILE"
|
||||
systemctl daemon-reload
|
||||
sleep 0.3
|
||||
|
||||
echo "70"; echo "# Removendo configuração do Unbound..."
|
||||
remover_configuracao_unbound
|
||||
sleep 0.3
|
||||
|
||||
echo "90"; echo "# Removendo arquivos..."
|
||||
rm -rf "$INSTALL_DIR"
|
||||
sleep 0.3
|
||||
|
||||
echo "100"; echo "# Concluído!"
|
||||
} | whiptail --title "DNSBlock Agent - Desinstalação" --gauge "Removendo DNSBlock Agent..." 8 60 0
|
||||
|
||||
whiptail --title "Desinstalação Concluída" \
|
||||
--msgbox "O DNSBlock Agent foi completamente removido do sistema." 8 55
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# MENU PRINCIPAL
|
||||
# ============================================================================
|
||||
|
||||
menu_principal() {
|
||||
local opcao
|
||||
|
||||
opcao=$(whiptail --title "DNSBlock Agent" \
|
||||
--menu "Selecione uma opção:" 15 60 4 \
|
||||
"1" "Instalar DNSBlock Agent" \
|
||||
"2" "Desinstalar DNSBlock Agent" \
|
||||
"3" "Sair" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
local status=$?
|
||||
|
||||
if [ $status -ne 0 ] || [ "$opcao" = "3" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$opcao" in
|
||||
1) instalar ;;
|
||||
2) desinstalar ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# INÍCIO DO SCRIPT
|
||||
# ============================================================================
|
||||
|
||||
# Verificar root
|
||||
verificar_root
|
||||
|
||||
# Processar argumentos
|
||||
case "${1:-}" in
|
||||
install)
|
||||
instalar
|
||||
;;
|
||||
uninstall|remove)
|
||||
desinstalar
|
||||
;;
|
||||
--help|-h)
|
||||
echo ""
|
||||
echo "DNSBlock Agent - Script de Instalação"
|
||||
echo ""
|
||||
echo "Uso: $0 [install|uninstall]"
|
||||
echo ""
|
||||
echo "Opções:"
|
||||
echo " install Instalar o DNSBlock Agent"
|
||||
echo " uninstall Desinstalar o DNSBlock Agent"
|
||||
echo " --help Exibir esta mensagem"
|
||||
echo ""
|
||||
echo "Se executado sem argumentos, exibe o menu interativo."
|
||||
echo ""
|
||||
;;
|
||||
"")
|
||||
menu_principal
|
||||
;;
|
||||
*)
|
||||
echo "Opção inválida: $1"
|
||||
echo "Use --help para ver as opções disponíveis."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user