diff --git a/install.sh b/install.sh index ad09538..a39dd5c 100755 --- a/install.sh +++ b/install.sh @@ -462,6 +462,14 @@ ExecStart=/opt/zoraxy/zoraxy -plugin=/opt/zoraxy/plugins Restart=on-failure RestartSec=5 +# Security hardening +ProtectSystem=full +PrivateTmp=true + +# Capabilities: bind low ports + talk to systemd for plugin reloads +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SYS_ADMIN +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SYS_ADMIN + [Install] WantedBy=multi-user.target ZORAXY_SVC @@ -533,15 +541,11 @@ install_plugin() { # Set group on plugin binary dir chgrp -R "$group" "$plugin_dir" 2>/dev/null || true - # Sudoers for reload - local sudoers_file="/etc/sudoers.d/dnsmasq-edit" - if [ ! -f "$sudoers_file" ]; then - cat > "$sudoers_file" << 'SUDO_EOF' -# Allow dnsmasq-edit group to reload dnsmasq without a password -%dnsmasq-edit ALL=(root) NOPASSWD: /usr/bin/systemctl reload dnsmasq, /usr/bin/systemctl restart dnsmasq, /usr/sbin/service dnsmasq reload, /usr/sbin/service dnsmasq restart -SUDO_EOF - chmod 0440 "$sudoers_file" - fi + # Note: reload uses Linux capabilities (CAP_SYS_ADMIN), not sudo. + # The Zoraxy systemd service must include: + # CapabilityBoundingSet=CAP_SYS_ADMIN + # AmbientCapabilities=CAP_SYS_ADMIN + # (already configured by this installer). log "Plugin installed at: $plugin_dir" } diff --git a/server.go b/server.go index ff3262f..7d01c97 100644 --- a/server.go +++ b/server.go @@ -24,8 +24,8 @@ var ( // Override via environment: LEASE_FILE, CONF_FILE, RELOAD_CMD, RELOAD_ARGS leasesFile = envOrDefault("LEASE_FILE", "/opt/zoraxy/conf/dhcp/dnsmasq.leases") confFile = envOrDefault("CONF_FILE", "/opt/zoraxy/conf/dhcp/dnsmasq.conf") - reloadCmd = envOrDefault("RELOAD_CMD", "sudo") - reloadArgs = strings.Fields(envOrDefault("RELOAD_ARGS", "systemctl reload dnsmasq")) + reloadCmd = envOrDefault("RELOAD_CMD", "/usr/bin/systemctl") + reloadArgs = strings.Fields(envOrDefault("RELOAD_ARGS", "reload dnsmasq")) ) func envOrDefault(key, fallback string) string {