commit
ed12f106c4
@ -188,9 +188,13 @@ return baseclass.extend({
|
|||||||
callPresets(),
|
callPresets(),
|
||||||
callBandwidth()
|
callBandwidth()
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
|
// Handle RPC expect unwrapping - results may be array or object
|
||||||
|
var presetsData = results[1] || [];
|
||||||
|
var presets = Array.isArray(presetsData) ? presetsData : (presetsData.presets || []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: results[0] || {},
|
status: results[0] || {},
|
||||||
presets: (results[1] || {}).presets || [],
|
presets: presets,
|
||||||
bandwidth: results[2] || {}
|
bandwidth: results[2] || {}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -203,9 +207,13 @@ return baseclass.extend({
|
|||||||
callCircuits(),
|
callCircuits(),
|
||||||
callBandwidth()
|
callBandwidth()
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
|
// Handle RPC expect unwrapping - results[1] may be array or object
|
||||||
|
var circuitsData = results[1] || [];
|
||||||
|
var circuits = Array.isArray(circuitsData) ? circuitsData : (circuitsData.circuits || []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: results[0] || {},
|
status: results[0] || {},
|
||||||
circuits: (results[1] || {}).circuits || [],
|
circuits: circuits,
|
||||||
bandwidth: results[2] || {}
|
bandwidth: results[2] || {}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -176,7 +176,8 @@ return view.extend({
|
|||||||
|
|
||||||
render: function(data) {
|
render: function(data) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var services = data.services || [];
|
// Handle RPC expect unwrapping - data may be array or object
|
||||||
|
var services = Array.isArray(data) ? data : (data.services || []);
|
||||||
|
|
||||||
var view = E('div', { 'class': 'tor-dashboard' }, [
|
var view = E('div', { 'class': 'tor-dashboard' }, [
|
||||||
E('link', { 'rel': 'stylesheet', 'href': L.resource('tor-shield/dashboard.css') }),
|
E('link', { 'rel': 'stylesheet', 'href': L.resource('tor-shield/dashboard.css') }),
|
||||||
|
|||||||
@ -7,20 +7,40 @@
|
|||||||
. /usr/share/libubox/jshn.sh
|
. /usr/share/libubox/jshn.sh
|
||||||
|
|
||||||
CONFIG="tor-shield"
|
CONFIG="tor-shield"
|
||||||
TOR_CONTROL="/var/run/tor/control"
|
TOR_RUN="/var/run/tor"
|
||||||
|
TOR_CONTROL="$TOR_RUN/control"
|
||||||
TOR_DATA="/var/lib/tor"
|
TOR_DATA="/var/lib/tor"
|
||||||
|
|
||||||
# Send command to Tor control socket
|
# Send command to Tor control socket with cookie auth
|
||||||
tor_control() {
|
tor_control() {
|
||||||
if [ ! -S "$TOR_CONTROL" ]; then
|
if [ ! -S "$TOR_CONTROL" ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
echo -e "$1" | nc -U "$TOR_CONTROL" 2>/dev/null
|
|
||||||
|
# Read cookie for authentication
|
||||||
|
local cookie=""
|
||||||
|
local cookie_file="$TOR_RUN/control_auth_cookie"
|
||||||
|
if [ -f "$cookie_file" ]; then
|
||||||
|
cookie=$(hexdump -e '32/1 "%02x"' "$cookie_file" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use socat for Unix socket (BusyBox nc doesn't support -U)
|
||||||
|
# Send AUTHENTICATE first, then the actual command
|
||||||
|
{
|
||||||
|
[ -n "$cookie" ] && echo "AUTHENTICATE $cookie"
|
||||||
|
echo "$1"
|
||||||
|
} | socat - UNIX-CONNECT:"$TOR_CONTROL" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if Tor is running
|
# Check if Tor is running
|
||||||
is_running() {
|
is_running() {
|
||||||
pgrep tor >/dev/null 2>&1
|
# Check for tor process (procd manages the process, no pid file)
|
||||||
|
pgrep -f "/usr/sbin/tor" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if tor-shield control socket is available
|
||||||
|
has_control() {
|
||||||
|
[ -S "$TOR_CONTROL" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get bootstrap percentage
|
# Get bootstrap percentage
|
||||||
@ -49,45 +69,55 @@ get_status() {
|
|||||||
# Running state
|
# Running state
|
||||||
if is_running; then
|
if is_running; then
|
||||||
json_add_boolean "running" 1
|
json_add_boolean "running" 1
|
||||||
|
json_add_boolean "has_control" "$(has_control && echo 1 || echo 0)"
|
||||||
|
|
||||||
# Bootstrap percentage
|
# Bootstrap percentage (only if control socket available)
|
||||||
local bootstrap=$(get_bootstrap)
|
local bootstrap=0
|
||||||
|
if has_control; then
|
||||||
|
bootstrap=$(get_bootstrap)
|
||||||
|
fi
|
||||||
json_add_int "bootstrap" "${bootstrap:-0}"
|
json_add_int "bootstrap" "${bootstrap:-0}"
|
||||||
|
|
||||||
# Get exit IP if bootstrapped
|
# Get exit IP if bootstrapped
|
||||||
if [ "$bootstrap" -ge 100 ]; then
|
if [ "$bootstrap" -ge 100 ]; then
|
||||||
local socks_port
|
local socks_port
|
||||||
config_get socks_port socks port '9050'
|
config_get socks_port socks port '9050'
|
||||||
local exit_ip=$(curl -s --max-time 10 --socks5-hostname 127.0.0.1:$socks_port https://check.torproject.org/api/ip 2>/dev/null | jsonfilter -e '@.IP' 2>/dev/null)
|
# Single curl call for both IP and IsTor
|
||||||
|
local tor_check=$(curl -s --max-time 10 --socks5-hostname 127.0.0.1:$socks_port https://check.torproject.org/api/ip 2>/dev/null)
|
||||||
|
local exit_ip=$(echo "$tor_check" | jsonfilter -e '@.IP' 2>/dev/null)
|
||||||
json_add_string "exit_ip" "${exit_ip:-unknown}"
|
json_add_string "exit_ip" "${exit_ip:-unknown}"
|
||||||
|
|
||||||
# Check if using Tor
|
# Check if using Tor
|
||||||
local is_tor=$(curl -s --max-time 10 --socks5-hostname 127.0.0.1:$socks_port https://check.torproject.org/api/ip 2>/dev/null | jsonfilter -e '@.IsTor' 2>/dev/null)
|
local is_tor=$(echo "$tor_check" | jsonfilter -e '@.IsTor' 2>/dev/null)
|
||||||
json_add_boolean "is_tor" "$([ "$is_tor" = "true" ] && echo 1 || echo 0)"
|
json_add_boolean "is_tor" "$([ "$is_tor" = "true" ] && echo 1 || echo 0)"
|
||||||
|
|
||||||
# Get circuit count
|
# Get circuit count (only if control available)
|
||||||
local circuits=$(tor_control "GETINFO circuit-status" | grep -c "BUILT" 2>/dev/null)
|
if has_control; then
|
||||||
json_add_int "circuit_count" "${circuits:-0}"
|
local circuits=$(tor_control "GETINFO circuit-status" | grep -c "BUILT" 2>/dev/null)
|
||||||
|
json_add_int "circuit_count" "${circuits:-0}"
|
||||||
|
|
||||||
# Get bandwidth
|
# Get bandwidth
|
||||||
local bw_read=$(tor_control "GETINFO traffic/read" | grep "250" | awk '{print $2}')
|
local bw_read=$(tor_control "GETINFO traffic/read" | grep "250" | awk '{print $2}')
|
||||||
local bw_written=$(tor_control "GETINFO traffic/written" | grep "250" | awk '{print $2}')
|
local bw_written=$(tor_control "GETINFO traffic/written" | grep "250" | awk '{print $2}')
|
||||||
json_add_int "bytes_read" "${bw_read:-0}"
|
json_add_int "bytes_read" "${bw_read:-0}"
|
||||||
json_add_int "bytes_written" "${bw_written:-0}"
|
json_add_int "bytes_written" "${bw_written:-0}"
|
||||||
|
else
|
||||||
|
json_add_int "circuit_count" 0
|
||||||
|
json_add_int "bytes_read" 0
|
||||||
|
json_add_int "bytes_written" 0
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Uptime from pid file
|
# Uptime from process start time
|
||||||
local pidfile="/var/run/tor/tor.pid"
|
local pid=$(pgrep -f "/usr/sbin/tor" | head -1)
|
||||||
if [ -f "$pidfile" ]; then
|
if [ -n "$pid" ] && [ -d "/proc/$pid" ]; then
|
||||||
local pid=$(cat "$pidfile")
|
local start_time=$(stat -c %Y "/proc/$pid" 2>/dev/null)
|
||||||
if [ -d "/proc/$pid" ]; then
|
local now=$(date +%s)
|
||||||
local start_time=$(stat -c %Y "/proc/$pid" 2>/dev/null)
|
json_add_int "uptime" "$((now - start_time))"
|
||||||
local now=$(date +%s)
|
|
||||||
json_add_int "uptime" "$((now - start_time))"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
json_add_boolean "running" 0
|
json_add_boolean "running" 0
|
||||||
|
json_add_boolean "has_control" 0
|
||||||
json_add_int "bootstrap" 0
|
json_add_int "bootstrap" 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -98,9 +128,11 @@ get_status() {
|
|||||||
json_add_boolean "bridges_enabled" "$bridges_enabled"
|
json_add_boolean "bridges_enabled" "$bridges_enabled"
|
||||||
json_add_string "bridge_type" "$bridge_type"
|
json_add_string "bridge_type" "$bridge_type"
|
||||||
|
|
||||||
# Get real IP
|
# Get real IP (try multiple services as fallback)
|
||||||
local real_ip=$(curl -s --max-time 5 https://ipinfo.io/ip 2>/dev/null)
|
local real_ip=$(curl -s --max-time 5 https://api.ipify.org 2>/dev/null)
|
||||||
json_add_string "real_ip" "${real_ip:-unknown}"
|
[ -z "$real_ip" ] && real_ip=$(curl -s --max-time 5 https://ifconfig.me/ip 2>/dev/null)
|
||||||
|
[ -z "$real_ip" ] && real_ip="unknown"
|
||||||
|
json_add_string "real_ip" "$real_ip"
|
||||||
|
|
||||||
json_dump
|
json_dump
|
||||||
}
|
}
|
||||||
@ -109,12 +141,15 @@ get_status() {
|
|||||||
do_enable() {
|
do_enable() {
|
||||||
read input
|
read input
|
||||||
json_load "$input"
|
json_load "$input"
|
||||||
|
|
||||||
|
# Get values from input BEFORE json_init
|
||||||
|
local preset
|
||||||
json_get_var preset preset
|
json_get_var preset preset
|
||||||
|
|
||||||
json_init
|
|
||||||
|
|
||||||
[ -z "$preset" ] && preset="anonymous"
|
[ -z "$preset" ] && preset="anonymous"
|
||||||
|
|
||||||
|
# Now initialize output JSON
|
||||||
|
json_init
|
||||||
|
|
||||||
# Load preset configuration
|
# Load preset configuration
|
||||||
config_load "$CONFIG"
|
config_load "$CONFIG"
|
||||||
|
|
||||||
@ -172,9 +207,18 @@ get_circuits() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local circuits=$(tor_control "GETINFO circuit-status")
|
# Check if control socket exists
|
||||||
|
if [ ! -S "$TOR_CONTROL" ]; then
|
||||||
|
json_close_array
|
||||||
|
json_dump
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
echo "$circuits" | grep "BUILT" | while read line; do
|
# Use temp file to avoid subshell issue with pipe
|
||||||
|
local TMP_CIRCUITS="/tmp/tor_circuits_$$"
|
||||||
|
tor_control "GETINFO circuit-status" | grep "BUILT" > "$TMP_CIRCUITS" 2>/dev/null
|
||||||
|
|
||||||
|
while read line; do
|
||||||
local id=$(echo "$line" | awk '{print $1}')
|
local id=$(echo "$line" | awk '{print $1}')
|
||||||
local status=$(echo "$line" | awk '{print $2}')
|
local status=$(echo "$line" | awk '{print $2}')
|
||||||
local path=$(echo "$line" | awk '{print $3}')
|
local path=$(echo "$line" | awk '{print $3}')
|
||||||
@ -189,7 +233,8 @@ get_circuits() {
|
|||||||
|
|
||||||
# Parse path into nodes
|
# Parse path into nodes
|
||||||
json_add_array "nodes"
|
json_add_array "nodes"
|
||||||
local IFS=','
|
local OLD_IFS="$IFS"
|
||||||
|
IFS=','
|
||||||
for node in $path; do
|
for node in $path; do
|
||||||
local fingerprint=$(echo "$node" | cut -d'~' -f1 | tr -d '$')
|
local fingerprint=$(echo "$node" | cut -d'~' -f1 | tr -d '$')
|
||||||
local name=$(echo "$node" | cut -d'~' -f2)
|
local name=$(echo "$node" | cut -d'~' -f2)
|
||||||
@ -199,12 +244,14 @@ get_circuits() {
|
|||||||
json_add_string "name" "${name:-$fingerprint}"
|
json_add_string "name" "${name:-$fingerprint}"
|
||||||
json_close_object
|
json_close_object
|
||||||
done
|
done
|
||||||
|
IFS="$OLD_IFS"
|
||||||
json_close_array
|
json_close_array
|
||||||
|
|
||||||
json_close_object
|
json_close_object
|
||||||
fi
|
fi
|
||||||
done
|
done < "$TMP_CIRCUITS"
|
||||||
|
|
||||||
|
rm -f "$TMP_CIRCUITS"
|
||||||
json_close_array
|
json_close_array
|
||||||
json_dump
|
json_dump
|
||||||
}
|
}
|
||||||
@ -331,10 +378,14 @@ add_hidden_service_json() {
|
|||||||
add_hidden_service() {
|
add_hidden_service() {
|
||||||
read input
|
read input
|
||||||
json_load "$input"
|
json_load "$input"
|
||||||
|
|
||||||
|
# Get values from input BEFORE json_init
|
||||||
|
local name local_port virtual_port
|
||||||
json_get_var name name
|
json_get_var name name
|
||||||
json_get_var local_port local_port
|
json_get_var local_port local_port
|
||||||
json_get_var virtual_port virtual_port
|
json_get_var virtual_port virtual_port
|
||||||
|
|
||||||
|
# Now initialize output JSON
|
||||||
json_init
|
json_init
|
||||||
|
|
||||||
if [ -z "$name" ]; then
|
if [ -z "$name" ]; then
|
||||||
@ -368,8 +419,12 @@ add_hidden_service() {
|
|||||||
remove_hidden_service() {
|
remove_hidden_service() {
|
||||||
read input
|
read input
|
||||||
json_load "$input"
|
json_load "$input"
|
||||||
|
|
||||||
|
# Get values from input BEFORE json_init
|
||||||
|
local name
|
||||||
json_get_var name name
|
json_get_var name name
|
||||||
|
|
||||||
|
# Now initialize output JSON
|
||||||
json_init
|
json_init
|
||||||
|
|
||||||
if [ -z "$name" ]; then
|
if [ -z "$name" ]; then
|
||||||
@ -535,9 +590,13 @@ add_bridge_json() {
|
|||||||
set_bridges() {
|
set_bridges() {
|
||||||
read input
|
read input
|
||||||
json_load "$input"
|
json_load "$input"
|
||||||
|
|
||||||
|
# Get values from input BEFORE json_init
|
||||||
|
local enabled type
|
||||||
json_get_var enabled enabled
|
json_get_var enabled enabled
|
||||||
json_get_var type type
|
json_get_var type type
|
||||||
|
|
||||||
|
# Now initialize output JSON
|
||||||
json_init
|
json_init
|
||||||
|
|
||||||
[ -n "$enabled" ] && uci set tor-shield.bridges.enabled="$enabled"
|
[ -n "$enabled" ] && uci set tor-shield.bridges.enabled="$enabled"
|
||||||
@ -612,9 +671,9 @@ save_settings() {
|
|||||||
read input
|
read input
|
||||||
json_load "$input"
|
json_load "$input"
|
||||||
|
|
||||||
json_init
|
# Get values from input BEFORE json_init (which wipes loaded JSON)
|
||||||
|
local mode dns_over_tor kill_switch socks_port trans_port dns_port
|
||||||
# Get values from input
|
local exit_nodes exclude_exit strict_nodes
|
||||||
json_get_var mode mode
|
json_get_var mode mode
|
||||||
json_get_var dns_over_tor dns_over_tor
|
json_get_var dns_over_tor dns_over_tor
|
||||||
json_get_var kill_switch kill_switch
|
json_get_var kill_switch kill_switch
|
||||||
@ -625,6 +684,9 @@ save_settings() {
|
|||||||
json_get_var exclude_exit exclude_exit_nodes
|
json_get_var exclude_exit exclude_exit_nodes
|
||||||
json_get_var strict_nodes strict_nodes
|
json_get_var strict_nodes strict_nodes
|
||||||
|
|
||||||
|
# Now initialize output JSON
|
||||||
|
json_init
|
||||||
|
|
||||||
# Apply settings
|
# Apply settings
|
||||||
[ -n "$mode" ] && uci set tor-shield.main.mode="$mode"
|
[ -n "$mode" ] && uci set tor-shield.main.mode="$mode"
|
||||||
[ -n "$dns_over_tor" ] && uci set tor-shield.main.dns_over_tor="$dns_over_tor"
|
[ -n "$dns_over_tor" ] && uci set tor-shield.main.dns_over_tor="$dns_over_tor"
|
||||||
|
|||||||
@ -222,8 +222,11 @@ return view.extend({
|
|||||||
|
|
||||||
return api.getAllData().then(L.bind(function(data) {
|
return api.getAllData().then(L.bind(function(data) {
|
||||||
var status = data.status || {};
|
var status = data.status || {};
|
||||||
var interfaces = (data.interfaces || {}).interfaces || [];
|
// Handle RPC expect unwrapping - may be array or object
|
||||||
var peers = (data.peers || {}).peers || [];
|
var interfacesData = data.interfaces || [];
|
||||||
|
var peersData = data.peers || [];
|
||||||
|
var interfaces = Array.isArray(interfacesData) ? interfacesData : (interfacesData.interfaces || []);
|
||||||
|
var peers = Array.isArray(peersData) ? peersData : (peersData.peers || []);
|
||||||
|
|
||||||
this.updateStats(status);
|
this.updateStats(status);
|
||||||
this.updatePeers(peers);
|
this.updatePeers(peers);
|
||||||
@ -240,8 +243,11 @@ return view.extend({
|
|||||||
render: function(data) {
|
render: function(data) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var status = data.status || {};
|
var status = data.status || {};
|
||||||
var interfaces = (data.interfaces || {}).interfaces || [];
|
// Handle RPC expect unwrapping - may be array or object
|
||||||
var peers = (data.peers || {}).peers || [];
|
var interfacesData = data.interfaces || [];
|
||||||
|
var peersData = data.peers || [];
|
||||||
|
var interfaces = Array.isArray(interfacesData) ? interfacesData : (interfacesData.interfaces || []);
|
||||||
|
var peers = Array.isArray(peersData) ? peersData : (peersData.peers || []);
|
||||||
|
|
||||||
// Store peer descriptions
|
// Store peer descriptions
|
||||||
this.peerDescriptions = data.descriptions || {};
|
this.peerDescriptions = data.descriptions || {};
|
||||||
|
|||||||
@ -178,10 +178,14 @@ return baseclass.extend({
|
|||||||
callGetTraffic(),
|
callGetTraffic(),
|
||||||
callPeerDescriptions()
|
callPeerDescriptions()
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
|
// Handle RPC expect unwrapping - results may be array or object
|
||||||
|
var peersData = results[1] || [];
|
||||||
|
var interfacesData = results[2] || [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: results[0] || {},
|
status: results[0] || {},
|
||||||
peers: results[1] || { peers: [] },
|
peers: Array.isArray(peersData) ? peersData : (peersData.peers || []),
|
||||||
interfaces: results[2] || { interfaces: [] },
|
interfaces: Array.isArray(interfacesData) ? interfacesData : (interfacesData.interfaces || []),
|
||||||
traffic: results[3] || {},
|
traffic: results[3] || {},
|
||||||
descriptions: (results[4] || {}).descriptions || {}
|
descriptions: (results[4] || {}).descriptions || {}
|
||||||
};
|
};
|
||||||
@ -196,10 +200,14 @@ return baseclass.extend({
|
|||||||
callBandwidthRates(),
|
callBandwidthRates(),
|
||||||
callPeerDescriptions()
|
callPeerDescriptions()
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
|
// Handle RPC expect unwrapping - results may be array or object
|
||||||
|
var peersData = results[1] || [];
|
||||||
|
var ratesData = results[2] || [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: results[0] || {},
|
status: results[0] || {},
|
||||||
peers: results[1] || { peers: [] },
|
peers: Array.isArray(peersData) ? peersData : (peersData.peers || []),
|
||||||
rates: (results[2] || {}).rates || [],
|
rates: Array.isArray(ratesData) ? ratesData : (ratesData.rates || []),
|
||||||
descriptions: (results[3] || {}).descriptions || {}
|
descriptions: (results[3] || {}).descriptions || {}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=secubox-app-haproxy
|
PKG_NAME:=secubox-app-haproxy
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=13
|
PKG_RELEASE:=14
|
||||||
|
|
||||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||||
PKG_LICENSE:=MIT
|
PKG_LICENSE:=MIT
|
||||||
@ -50,11 +50,28 @@ define Package/secubox-app-haproxy/install
|
|||||||
|
|
||||||
$(INSTALL_DIR) $(1)/usr/sbin
|
$(INSTALL_DIR) $(1)/usr/sbin
|
||||||
$(INSTALL_BIN) ./files/usr/sbin/haproxyctl $(1)/usr/sbin/haproxyctl
|
$(INSTALL_BIN) ./files/usr/sbin/haproxyctl $(1)/usr/sbin/haproxyctl
|
||||||
|
$(INSTALL_BIN) ./files/usr/sbin/haproxy-sync-certs $(1)/usr/sbin/haproxy-sync-certs
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/acme/deploy
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/acme/deploy/haproxy.sh $(1)/usr/lib/acme/deploy/haproxy.sh
|
||||||
|
|
||||||
$(INSTALL_DIR) $(1)/usr/share/haproxy/templates
|
$(INSTALL_DIR) $(1)/usr/share/haproxy/templates
|
||||||
$(INSTALL_DATA) ./files/usr/share/haproxy/templates/* $(1)/usr/share/haproxy/templates/
|
$(INSTALL_DATA) ./files/usr/share/haproxy/templates/* $(1)/usr/share/haproxy/templates/
|
||||||
|
|
||||||
$(INSTALL_DIR) $(1)/usr/share/haproxy/certs
|
$(INSTALL_DIR) $(1)/usr/share/haproxy/certs
|
||||||
|
|
||||||
|
# Add cron job for certificate sync after ACME renewals
|
||||||
|
$(INSTALL_DIR) $(1)/etc/cron.d
|
||||||
|
echo "# Sync ACME certs to HAProxy after renewals" > $(1)/etc/cron.d/haproxy-certs
|
||||||
|
echo "15 3 * * * root /usr/sbin/haproxy-sync-certs >/dev/null 2>&1" >> $(1)/etc/cron.d/haproxy-certs
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-haproxy/postinst
|
||||||
|
#!/bin/sh
|
||||||
|
[ -n "$${IPKG_INSTROOT}" ] && exit 0
|
||||||
|
# Sync existing ACME certificates on install
|
||||||
|
/usr/sbin/haproxy-sync-certs 2>/dev/null || true
|
||||||
|
exit 0
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call BuildPackage,secubox-app-haproxy))
|
$(eval $(call BuildPackage,secubox-app-haproxy))
|
||||||
|
|||||||
@ -16,6 +16,9 @@ start_service() {
|
|||||||
|
|
||||||
[ "$enabled" = "1" ] || return 0
|
[ "$enabled" = "1" ] || return 0
|
||||||
|
|
||||||
|
# Sync ACME certificates to HAProxy format before starting
|
||||||
|
/usr/sbin/haproxy-sync-certs 2>/dev/null || true
|
||||||
|
|
||||||
procd_open_instance
|
procd_open_instance
|
||||||
procd_set_param command "$PROG" service-run
|
procd_set_param command "$PROG" service-run
|
||||||
procd_set_param respawn 3600 5 0
|
procd_set_param respawn 3600 5 0
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ACME deploy hook for HAProxy
|
||||||
|
# Combines fullchain + private key into single .pem file
|
||||||
|
# Usage: Called by acme.sh after certificate issuance/renewal
|
||||||
|
|
||||||
|
HAPROXY_CERTS_DIR="/srv/haproxy/certs"
|
||||||
|
|
||||||
|
# acme.sh passes these environment variables:
|
||||||
|
# DOMAIN - the domain name
|
||||||
|
# CERT_PATH - path to the domain certificate
|
||||||
|
# KEY_PATH - path to the domain private key
|
||||||
|
# CA_PATH - path to the intermediate CA certificate
|
||||||
|
# FULLCHAIN_PATH - path to the full chain certificate
|
||||||
|
# CERT_KEY_PATH - same as KEY_PATH
|
||||||
|
|
||||||
|
deploy() {
|
||||||
|
local domain="$1"
|
||||||
|
local key_path="$2"
|
||||||
|
local cert_path="$3"
|
||||||
|
local ca_path="$4"
|
||||||
|
local fullchain_path="$5"
|
||||||
|
|
||||||
|
[ -z "$domain" ] && { echo "Error: domain required"; return 1; }
|
||||||
|
|
||||||
|
mkdir -p "$HAPROXY_CERTS_DIR"
|
||||||
|
|
||||||
|
# Use fullchain if available, otherwise use cert + ca
|
||||||
|
local combined_cert=""
|
||||||
|
if [ -n "$fullchain_path" ] && [ -f "$fullchain_path" ]; then
|
||||||
|
combined_cert="$fullchain_path"
|
||||||
|
elif [ -n "$cert_path" ] && [ -f "$cert_path" ]; then
|
||||||
|
combined_cert="$cert_path"
|
||||||
|
else
|
||||||
|
echo "Error: No certificate file found for $domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$key_path" ] || [ ! -f "$key_path" ]; then
|
||||||
|
echo "Error: No key file found for $domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Combine fullchain + private key for HAProxy
|
||||||
|
echo "Deploying certificate for $domain to HAProxy..."
|
||||||
|
cat "$combined_cert" "$key_path" > "$HAPROXY_CERTS_DIR/$domain.pem"
|
||||||
|
chmod 600 "$HAPROXY_CERTS_DIR/$domain.pem"
|
||||||
|
|
||||||
|
echo "Certificate deployed: $HAPROXY_CERTS_DIR/$domain.pem"
|
||||||
|
|
||||||
|
# Reload HAProxy if running
|
||||||
|
if [ -x /etc/init.d/haproxy ]; then
|
||||||
|
/etc/init.d/haproxy reload 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Entry point for acme.sh deploy hook
|
||||||
|
deploy "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Sync ACME certificates to HAProxy format
|
||||||
|
# Combines fullchain + private key into .pem files
|
||||||
|
# Called by ACME renewal or manually via haproxyctl
|
||||||
|
|
||||||
|
ACME_DIR="/etc/acme"
|
||||||
|
HAPROXY_CERTS_DIR="/srv/haproxy/certs"
|
||||||
|
|
||||||
|
log_info() { echo "[haproxy-sync-certs] $*"; logger -t haproxy-sync-certs "$*"; }
|
||||||
|
log_error() { echo "[haproxy-sync-certs] ERROR: $*" >&2; logger -t haproxy-sync-certs -p err "$*"; }
|
||||||
|
|
||||||
|
mkdir -p "$HAPROXY_CERTS_DIR"
|
||||||
|
|
||||||
|
# Find all ACME certificates and deploy them
|
||||||
|
for domain_dir in "$ACME_DIR"/*/; do
|
||||||
|
[ -d "$domain_dir" ] || continue
|
||||||
|
|
||||||
|
# Skip non-domain directories
|
||||||
|
case "$(basename "$domain_dir")" in
|
||||||
|
ca|*.ecc) continue ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
domain=$(basename "$domain_dir")
|
||||||
|
fullchain="$domain_dir/fullchain.cer"
|
||||||
|
key="$domain_dir/${domain}.key"
|
||||||
|
|
||||||
|
# Try alternate paths
|
||||||
|
[ -f "$fullchain" ] || fullchain="$domain_dir/fullchain.pem"
|
||||||
|
[ -f "$key" ] || key="$domain_dir/privkey.pem"
|
||||||
|
[ -f "$key" ] || key="$domain_dir/${domain}.key"
|
||||||
|
|
||||||
|
if [ -f "$fullchain" ] && [ -f "$key" ]; then
|
||||||
|
log_info "Syncing certificate for $domain"
|
||||||
|
cat "$fullchain" "$key" > "$HAPROXY_CERTS_DIR/$domain.pem"
|
||||||
|
chmod 600 "$HAPROXY_CERTS_DIR/$domain.pem"
|
||||||
|
else
|
||||||
|
log_error "Missing cert or key for $domain (fullchain=$fullchain, key=$key)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_info "Certificate sync complete"
|
||||||
|
|
||||||
|
# Reload HAProxy if running
|
||||||
|
if pgrep -x haproxy >/dev/null 2>&1 || lxc-info -n haproxy -s 2>/dev/null | grep -q RUNNING; then
|
||||||
|
log_info "Reloading HAProxy..."
|
||||||
|
/etc/init.d/haproxy reload 2>/dev/null || true
|
||||||
|
fi
|
||||||
@ -630,8 +630,13 @@ cmd_cert_add() {
|
|||||||
--home "$LE_WORKING_DIR" \
|
--home "$LE_WORKING_DIR" \
|
||||||
--cert-file "$CERTS_PATH/$domain.crt" \
|
--cert-file "$CERTS_PATH/$domain.crt" \
|
||||||
--key-file "$CERTS_PATH/$domain.key" \
|
--key-file "$CERTS_PATH/$domain.key" \
|
||||||
--fullchain-file "$CERTS_PATH/$domain.pem" \
|
--fullchain-file "$CERTS_PATH/$domain.fullchain.pem" \
|
||||||
--reloadcmd "/etc/init.d/haproxy reload" 2>/dev/null || true
|
--reloadcmd "/etc/init.d/haproxy reload" 2>/dev/null || true
|
||||||
|
|
||||||
|
# HAProxy needs combined file: fullchain + private key
|
||||||
|
log_info "Creating combined PEM for HAProxy..."
|
||||||
|
cat "$CERTS_PATH/$domain.fullchain.pem" "$CERTS_PATH/$domain.key" > "$CERTS_PATH/$domain.pem"
|
||||||
|
chmod 600 "$CERTS_PATH/$domain.pem"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Restart HAProxy if it was running
|
# Restart HAProxy if it was running
|
||||||
|
|||||||
@ -22,7 +22,7 @@ define Package/secubox-app-tor
|
|||||||
PKGARCH:=all
|
PKGARCH:=all
|
||||||
SUBMENU:=SecuBox Apps
|
SUBMENU:=SecuBox Apps
|
||||||
TITLE:=SecuBox Tor Shield
|
TITLE:=SecuBox Tor Shield
|
||||||
DEPENDS:=+tor +tor-geoip +iptables +curl +jsonfilter
|
DEPENDS:=+tor +tor-geoip +iptables +curl +jsonfilter +socat
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/secubox-app-tor/description
|
define Package/secubox-app-tor/description
|
||||||
|
|||||||
@ -37,7 +37,13 @@ generate_torrc() {
|
|||||||
config_get strict_nodes security strict_nodes '0'
|
config_get strict_nodes security strict_nodes '0'
|
||||||
|
|
||||||
mkdir -p "$TOR_RUN" "$TOR_DATA"
|
mkdir -p "$TOR_RUN" "$TOR_DATA"
|
||||||
chmod 700 "$TOR_DATA"
|
|
||||||
|
# Clean up stale files that may have wrong ownership
|
||||||
|
rm -f "$TOR_RUN/tor.pid" "$TOR_RUN/control" "$TOR_RUN/control_auth_cookie" 2>/dev/null
|
||||||
|
rm -f "$TOR_DATA/lock" 2>/dev/null
|
||||||
|
|
||||||
|
chown tor:tor "$TOR_RUN" "$TOR_DATA"
|
||||||
|
chmod 700 "$TOR_RUN" "$TOR_DATA"
|
||||||
|
|
||||||
cat > "$TORRC" << EOF
|
cat > "$TORRC" << EOF
|
||||||
# SecuBox Tor Shield - Auto-generated config
|
# SecuBox Tor Shield - Auto-generated config
|
||||||
@ -45,10 +51,12 @@ generate_torrc() {
|
|||||||
|
|
||||||
User tor
|
User tor
|
||||||
DataDirectory $TOR_DATA
|
DataDirectory $TOR_DATA
|
||||||
PidFile $TOR_RUN/tor.pid
|
Log notice syslog
|
||||||
Log notice file /var/log/tor.log
|
|
||||||
ControlSocket $TOR_RUN/control
|
ControlSocket $TOR_RUN/control
|
||||||
ControlSocketsGroupWritable 1
|
ControlSocketsGroupWritable 1
|
||||||
|
CookieAuthentication 1
|
||||||
|
CookieAuthFile $TOR_RUN/control_auth_cookie
|
||||||
|
CookieAuthFileGroupReadable 1
|
||||||
|
|
||||||
# SOCKS proxy
|
# SOCKS proxy
|
||||||
SocksPort $socks_addr:$socks_port
|
SocksPort $socks_addr:$socks_port
|
||||||
@ -79,15 +87,23 @@ VirtualAddrNetworkIPv4 10.192.0.0/10
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bridge configuration
|
# Bridge configuration - only enable if bridges are configured
|
||||||
if [ "$bridges_enabled" = "1" ]; then
|
if [ "$bridges_enabled" = "1" ]; then
|
||||||
cat >> "$TORRC" << EOF
|
# Count bridge lines first
|
||||||
|
BRIDGE_COUNT=0
|
||||||
|
count_bridge() { BRIDGE_COUNT=$((BRIDGE_COUNT + 1)); }
|
||||||
|
config_list_foreach bridges bridge_lines count_bridge
|
||||||
|
|
||||||
|
# Only add UseBridges if there are actual bridges configured
|
||||||
|
if [ "$BRIDGE_COUNT" -gt 0 ]; then
|
||||||
|
cat >> "$TORRC" << EOF
|
||||||
|
|
||||||
# Bridge mode
|
# Bridge mode
|
||||||
UseBridges 1
|
UseBridges 1
|
||||||
EOF
|
EOF
|
||||||
# Add bridge lines from config
|
# Add bridge lines from config
|
||||||
config_list_foreach bridges bridge_lines add_bridge_line
|
config_list_foreach bridges bridge_lines add_bridge_line
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Exit node restrictions
|
# Exit node restrictions
|
||||||
@ -111,6 +127,9 @@ EOF
|
|||||||
if [ -f /usr/share/tor/geoip6 ]; then
|
if [ -f /usr/share/tor/geoip6 ]; then
|
||||||
echo "GeoIPv6File /usr/share/tor/geoip6" >> "$TORRC"
|
echo "GeoIPv6File /usr/share/tor/geoip6" >> "$TORRC"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure torrc is readable by tor user
|
||||||
|
chown tor:tor "$TORRC"
|
||||||
}
|
}
|
||||||
|
|
||||||
add_bridge_line() {
|
add_bridge_line() {
|
||||||
@ -130,6 +149,7 @@ add_hidden_service() {
|
|||||||
|
|
||||||
local hs_dir="$TOR_DATA/hidden_service_$name"
|
local hs_dir="$TOR_DATA/hidden_service_$name"
|
||||||
mkdir -p "$hs_dir"
|
mkdir -p "$hs_dir"
|
||||||
|
chown tor:tor "$hs_dir"
|
||||||
chmod 700 "$hs_dir"
|
chmod 700 "$hs_dir"
|
||||||
|
|
||||||
cat >> "$TORRC" << EOF
|
cat >> "$TORRC" << EOF
|
||||||
@ -153,6 +173,10 @@ setup_iptables() {
|
|||||||
# Get Tor user ID
|
# Get Tor user ID
|
||||||
local tor_uid=$(id -u tor 2>/dev/null || echo "tor")
|
local tor_uid=$(id -u tor 2>/dev/null || echo "tor")
|
||||||
|
|
||||||
|
# Remove from OUTPUT chain first (to allow chain deletion)
|
||||||
|
iptables -t nat -D OUTPUT -j TOR_SHIELD 2>/dev/null
|
||||||
|
iptables -t filter -D OUTPUT -j TOR_SHIELD 2>/dev/null
|
||||||
|
|
||||||
# Clear existing Tor rules
|
# Clear existing Tor rules
|
||||||
iptables -t nat -F TOR_SHIELD 2>/dev/null
|
iptables -t nat -F TOR_SHIELD 2>/dev/null
|
||||||
iptables -t nat -X TOR_SHIELD 2>/dev/null
|
iptables -t nat -X TOR_SHIELD 2>/dev/null
|
||||||
@ -161,9 +185,9 @@ setup_iptables() {
|
|||||||
|
|
||||||
[ "$mode" = "transparent" ] || return 0
|
[ "$mode" = "transparent" ] || return 0
|
||||||
|
|
||||||
# Create chains
|
# Create chains (ignore "already exists" errors)
|
||||||
iptables -t nat -N TOR_SHIELD
|
iptables -t nat -N TOR_SHIELD 2>/dev/null || true
|
||||||
iptables -t filter -N TOR_SHIELD
|
iptables -t filter -N TOR_SHIELD 2>/dev/null || true
|
||||||
|
|
||||||
# Exclude Tor traffic
|
# Exclude Tor traffic
|
||||||
iptables -t nat -A TOR_SHIELD -m owner --uid-owner $tor_uid -j RETURN
|
iptables -t nat -A TOR_SHIELD -m owner --uid-owner $tor_uid -j RETURN
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user