change:
- adjust: blacklist / whitelist
- adjust: scripts for CLASH TUN
- fix: "network_mode" ( redirect: tcp only, / tproxy: for tcp+udp with tproxy, / mixed: mode with redirect[tcp] + tun[udp] )
Changes to be committed:
modified: box/scripts/box.inotify
modified: box/scripts/box.iptables
modified: box/scripts/box.service
modified: box/scripts/box.tool
modified: box/scripts/start.sh
modified: box/settings.ini
This commit is contained in:
@@ -7,7 +7,7 @@ service_path="/data/adb/box/scripts/box.service"
|
||||
iptables_path="/data/adb/box/scripts/box.iptables"
|
||||
data_box="/data/adb/box"
|
||||
run_path="/data/adb/box/run"
|
||||
now=$(date +"%I.%M %p %z")
|
||||
now=$(date +"%R")
|
||||
|
||||
events=$1
|
||||
monitor_dir=$2
|
||||
@@ -16,11 +16,11 @@ monitor_file=$3
|
||||
service_control() {
|
||||
if [ "${monitor_file}" = "disable" ]; then
|
||||
if [ "${events}" = "d" ]; then
|
||||
"${service_path}" start > "${run_path}/service.log" 2>> "${run_path}/service.log" && \
|
||||
"${iptables_path}" enable >> "${run_path}/service.log" 2>> "${run_path}/service.log"
|
||||
"${service_path}" start > "${run_path}/service.log" 2>&1 && \
|
||||
"${iptables_path}" enable >> "${run_path}/service.log" 2>&1
|
||||
elif [ "${events}" = "n" ]; then
|
||||
"${iptables_path}" disable >> "${run_path}/service.log" 2>> "${run_path}/service.log" && \
|
||||
"${service_path}" stop >> "${run_path}/service.log" 2>> "${run_path}/service.log"
|
||||
"${iptables_path}" disable >> "${run_path}/service.log" 2>&1 && \
|
||||
"${service_path}" stop >> "${run_path}/service.log" 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@ clash_dns_port=""
|
||||
tun_device=""
|
||||
|
||||
# Looking for value from "fake-ip-range: / listen: / tun_device" block in YAML / JSON configuration file
|
||||
clash_fake_ip_range=$(busybox awk '/fake-ip-range: / { print $2;found=1; exit } END{ if(!found) print "198.18.0.1/16" }' "${clash_config}" 2>/dev/null)
|
||||
clash_enhanced_mode=$(busybox awk '/enhanced-mode: / { print $2;found=1; exit } END{ if(!found) print "fake-ip" }' "${clash_config}" 2>/dev/null)
|
||||
clash_dns_port=$(busybox awk -F ':' '/listen:/ { print $3;found=1; exit } END{ if(!found) print "1053" }' "${clash_config}" 2>/dev/null)
|
||||
|
||||
if [ "${bin_name}" = "clash" ]; then
|
||||
tun_device=$(busybox awk '/device: / { print $2;found=1; exit } END{ if(!found) print "utun" }' "${clash_config}" 2>/dev/null)
|
||||
elif [ "${bin_name}" = "sing-box" ]; then
|
||||
tun_device=$(find "${data_dir}/sing-box/" -type f -name "*.json" -exec busybox awk -F'"' '/interface_name/{ if ($4 != "tun0") {print $4; found=1; exit} } END{ if(!found) print "tun0" }' {} \; 2>/dev/null | head -n 1)
|
||||
fi
|
||||
clash_fake_ip_range=$(busybox awk '/fake-ip-range: / { print $2;found=1; exit } END{ if(!found) print "198.18.0.1/16" }' "${clash_config}" 2>/dev/null)
|
||||
clash_enhanced_mode=$(busybox awk '/enhanced-mode: / { print $2;found=1; exit } END{ if(!found) print "fake-ip" }' "${clash_config}" 2>/dev/null)
|
||||
clash_dns_port=$(busybox awk -F ':' '/listen:/ { print $3;found=1; exit } END{ if(!found) print "1053" }' "${clash_config}" 2>/dev/null)
|
||||
|
||||
probe_empty () {
|
||||
if [ "${bin_name}" = "clash" ]; then
|
||||
@@ -147,7 +148,7 @@ start_redirect() {
|
||||
done
|
||||
|
||||
${iptables} -t nat -A BOX_EXTERNAL -p tcp -i lo -j REDIRECT --to-ports "${redir_port}"
|
||||
|
||||
|
||||
if [ "${ap_list}" != "" ]; then
|
||||
for ap in "${ap_list[@]}"; do
|
||||
${iptables} -t nat -A BOX_EXTERNAL -p tcp -i "${ap}" -j REDIRECT --to-ports "${redir_port}"
|
||||
@@ -192,19 +193,25 @@ start_redirect() {
|
||||
log info "proxy-mode: ${proxy_mode} < [ ${packages_list[*]} ] no transparent proxy."
|
||||
fi
|
||||
elif [ "${proxy_mode}" = "whitelist" ]; then
|
||||
# Route apps to Box
|
||||
# loop through the UID list
|
||||
while read -r appid; do
|
||||
# add iptables rules for TCP traffic
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j REDIRECT --to-ports "${redir_port}"
|
||||
done < "${uid_list[*]}"
|
||||
if [ "$(cat "${uid_list[@]}")" = "" ]; then
|
||||
# Route Everything
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}"
|
||||
log info "Transparent proxy for all apps."
|
||||
else
|
||||
# Route apps to Box
|
||||
# loop through the UID list
|
||||
while read -r appid; do
|
||||
# add iptables rules for TCP traffic
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j REDIRECT --to-ports "${redir_port}"
|
||||
done < "${uid_list[*]}"
|
||||
|
||||
# close the file handle for the UID list
|
||||
# exec <&-
|
||||
# close the file handle for the UID list
|
||||
# exec <&-
|
||||
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j REDIRECT --to-ports "${redir_port}"
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j REDIRECT --to-ports "${redir_port}"
|
||||
log info "proxy-mode: ${proxy_mode} < [ ${packages_list[*]} ] transparent proxy."
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j REDIRECT --to-ports "${redir_port}"
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j REDIRECT --to-ports "${redir_port}"
|
||||
log info "proxy-mode: ${proxy_mode} < [ ${packages_list[*]} ] transparent proxy."
|
||||
fi
|
||||
else
|
||||
log warn "proxy-mode: ${proxy_mode} < error."
|
||||
${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports "${redir_port}"
|
||||
@@ -269,8 +276,8 @@ start_tproxy() {
|
||||
# Bypass other if
|
||||
# Notice: Some interface is named with r_ / oem / nm_ / qcom_
|
||||
# It might need more complicated solution.
|
||||
${iptables} -t mangle -I BOX_EXTERNAL -i rmnet_data+ -j RETURN
|
||||
${iptables} -t mangle -I BOX_EXTERNAL -i ccmni+ -j RETURN
|
||||
# ${iptables} -t mangle -I BOX_EXTERNAL -i rmnet_data+ -j RETURN
|
||||
# ${iptables} -t mangle -I BOX_EXTERNAL -i ccmni+ -j RETURN
|
||||
|
||||
# Bypass intranet
|
||||
# Add rules for intranet subnets
|
||||
@@ -360,7 +367,7 @@ start_tproxy() {
|
||||
# ${iptables} -t mangle -A BOX_LOCAL -m owner ! --uid 0-99999999 -j DROP
|
||||
|
||||
if [ "${proxy_mode}" = "blacklist" ]; then
|
||||
if [ "$(cat ${uid_list[*]})" = "" ]; then
|
||||
if [ "$(cat ${uid_list[@]})" = "" ]; then
|
||||
# Route Everything
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-mark "${fwmark}"
|
||||
@@ -382,24 +389,31 @@ start_tproxy() {
|
||||
fi
|
||||
|
||||
elif [ "${proxy_mode}" = "whitelist" ]; then
|
||||
# Route apps to Box
|
||||
# loop through uid list and add iptables rule
|
||||
while read -r appid; do
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner "${appid}" -j MARK --set-mark "${fwmark}"
|
||||
done < "${uid_list[*]}"
|
||||
|
||||
# close the file handle for the UID list
|
||||
# exec <&-
|
||||
if [ "$(cat "${uid_list[@]}")" = "" ]; then
|
||||
# Route Everything
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-mark "${fwmark}"
|
||||
[ "${iptables}" != "ip6tables -w 64" ] && log info "transparent proxy for all apps."
|
||||
else
|
||||
# Route apps to Box
|
||||
# loop through uid list and add iptables rule
|
||||
while read -r appid; do
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner "${appid}" -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner "${appid}" -j MARK --set-mark "${fwmark}"
|
||||
done < "${uid_list[*]}"
|
||||
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 0 -j MARK --set-mark "${fwmark}"
|
||||
# Route dnsmasq to Box
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 1052 -j MARK --set-mark "${fwmark}"
|
||||
# Route DNS request to Box
|
||||
[ "${bin_name}" != "clash" ] && ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j MARK --set-mark "${fwmark}"
|
||||
[ "${iptables}" != "ip6tables -w 64" ] && log info "proxy-mode: ${proxy_mode} < [ ${packages_list[*]} ] transparent proxy."
|
||||
# close the file handle for the UID list
|
||||
# exec <&-
|
||||
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 0 -j MARK --set-mark "${fwmark}"
|
||||
# Route dnsmasq to Box
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j MARK --set-mark "${fwmark}"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 1052 -j MARK --set-mark "${fwmark}"
|
||||
# Route DNS request to Box
|
||||
[ "${bin_name}" != "clash" ] && ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j MARK --set-mark "${fwmark}"
|
||||
[ "${iptables}" != "ip6tables -w 64" ] && log info "proxy-mode: ${proxy_mode} < [ ${packages_list[*]} ] transparent proxy."
|
||||
fi
|
||||
else
|
||||
log debug "proxy-mode: ${proxy_mode} < error"
|
||||
${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-mark "${fwmark}"
|
||||
@@ -416,7 +430,7 @@ start_tproxy() {
|
||||
|
||||
${iptables} -t mangle -I PREROUTING -p tcp -m socket -j DIVERT
|
||||
|
||||
# # Disable QUIC
|
||||
# Disable QUIC
|
||||
if [ "${quic}" = "disable" ]; then
|
||||
${iptables} -A OUTPUT -p udp --dport 443 -j REJECT
|
||||
${iptables} -A OUTPUT -p udp --dport 80 -j REJECT
|
||||
@@ -438,14 +452,14 @@ start_tproxy() {
|
||||
${iptables} -t nat -F CLASH_DNS_EXTERNAL
|
||||
${iptables} -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}"
|
||||
${iptables} -t nat -I PREROUTING -j CLASH_DNS_EXTERNAL
|
||||
|
||||
|
||||
# Create and configure CLASH_DNS_LOCAL chain
|
||||
${iptables} -t nat -N CLASH_DNS_LOCAL
|
||||
${iptables} -t nat -F CLASH_DNS_LOCAL
|
||||
${iptables} -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner "${box_user}" --gid-owner "${box_group}" -j RETURN
|
||||
${iptables} -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports "${clash_dns_port}"
|
||||
${iptables} -t nat -I OUTPUT -j CLASH_DNS_LOCAL
|
||||
|
||||
|
||||
# Fix ICMP (ping)
|
||||
# This does not guarantee that the ping result is valid
|
||||
# Just that it returns a result
|
||||
@@ -457,7 +471,6 @@ start_tproxy() {
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
stop_tproxy() {
|
||||
if [ "${iptables}" != "ip6tables -w 64" ]; then
|
||||
ip rule del fwmark "${fwmark}" table "${table}" pref "${pref}"
|
||||
@@ -656,15 +669,15 @@ if [ "${proxy_mode}" != "tun" ]; then
|
||||
intranet+=($(ip address | busybox awk '/inet / && !/127\.0\.0\.1/ {print $2}'))
|
||||
start_redirect && log info "create iptables transparent proxy rules done." || { log error "create iptables transparent proxy rule failed." && stop_redirect >> /dev/null 2>&1; }
|
||||
if [ "${ipv6}" = "true" ]; then
|
||||
log debug "use IPv6."
|
||||
ipv6_enable
|
||||
iptables="ip6tables -w 64"
|
||||
intranet6+=($(ip address | busybox awk '/inet6/ && !/::1/ && !/fe80/ {print $2}'))
|
||||
forward -I || forward -D >> /dev/null 2>&1
|
||||
start_redirect && log info "create ip6tables transparent proxy rules done." || { log error "create ip6tables transparent proxy rule failed." && stop_redirect >> /dev/null 2>&1; }
|
||||
log debug "use IPv6."
|
||||
ipv6_enable
|
||||
iptables="ip6tables -w 64"
|
||||
intranet6+=($(ip address | busybox awk '/inet6/ && !/::1/ && !/fe80/ {print $2}'))
|
||||
forward -I || forward -D >> /dev/null 2>&1
|
||||
start_redirect && log info "create ip6tables transparent proxy rules done." || { log error "create ip6tables transparent proxy rule failed." && stop_redirect >> /dev/null 2>&1; }
|
||||
else
|
||||
disable_ipv6
|
||||
log warn "disable IPv6."
|
||||
disable_ipv6
|
||||
log warn "disable IPv6."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -4,22 +4,20 @@ scripts=$(realpath $0)
|
||||
scripts_dir=$(dirname ${scripts})
|
||||
source /data/adb/box/settings.ini
|
||||
|
||||
# Reads the enable value from the tun configuration
|
||||
# singbox_tun=$(find /data/adb/box/sing-box/ -name "*.json" -exec busybox awk -F':' '/"type":[[:space:]]*"tun"/{gsub(/^[[:space:]]+|[",[:space:]]+$/,"",$2); print $2}' {} \; | tr -d '"')
|
||||
clash_tun_status=$(busybox awk -F ': ' '/^tun: *$/{getline; print $2}' "${clash_config}")
|
||||
|
||||
delete_logs() {
|
||||
# Delete logs for each bin in the list
|
||||
log info "deleting & backup logs for ${bin_list[*]}"
|
||||
for bin in "${bin_list[@]}" ; do
|
||||
log info "deleting and backing up logs for ${bin_list[*]}"
|
||||
for bin in "${bin_list[@]}"; do
|
||||
if [ -f "${run_path}/${bin}.log" ]; then
|
||||
mv "${run_path}/${bin}.log" "${run_path}/${bin}-$(date +%Y-%m-%d-%H-%M-%S).log"
|
||||
fi
|
||||
done
|
||||
|
||||
# Delete other log files
|
||||
find "${run_path}" -type f \( -name "root" -o -name "*.yaml" -o -name "*.list" -o -name "*.inotify.log" -o -name "*-report.log" \) -exec rm -f {} \; || log warn "Error deleting other log files"
|
||||
|
||||
# Delete logs that are three days old or older
|
||||
find "${run_path}" -type f -name "*.log" -mtime +2 -exec rm -f {} \; || log warn "Error deleting old log"
|
||||
find "${run_path}" -type f -name "*.log" -mtime +2 -exec rm -f {} \; || log warn "Error deleting old logs"
|
||||
}
|
||||
|
||||
crontab_geo() {
|
||||
@@ -31,14 +29,18 @@ crontab_geo() {
|
||||
log debug "${bin_name} subscription (${auto_update_subscription})."
|
||||
fi
|
||||
else
|
||||
log info "Crontab geox & subscription is disabled."
|
||||
log info "Crontab geox and subscription is disabled."
|
||||
fi
|
||||
}
|
||||
|
||||
detected_port() {
|
||||
sleep 1
|
||||
[ "${port_detect}" = "true" ] && ${scripts_dir}/box.tool port || \
|
||||
log debug "${bin_name} skip port detected." && return 1
|
||||
if [ "${port_detect}" = "true" ]; then
|
||||
${scripts_dir}/box.tool port
|
||||
else
|
||||
log debug "${bin_name} skipped port detected."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
still_alive() {
|
||||
@@ -60,62 +62,38 @@ still_alive() {
|
||||
}
|
||||
|
||||
check_permission() {
|
||||
if [ "${box_user_group}" = "root:net_admin" ]; then
|
||||
if [ ! -f ${bin_path} ]; then
|
||||
log error "Kernel '${bin_name}' is missing."
|
||||
log error "Please download the '${bin_name}' kernel and place it in the ${bin_kernel}/ directory."
|
||||
exit 1
|
||||
fi
|
||||
if which ${bin_name} | grep -q "/system/bin/" ; then
|
||||
box_user=$(echo ${box_user_group} | busybox awk -F ':' '{print $1}')
|
||||
box_group=$(echo ${box_user_group} | busybox awk -F ':' '{print $2}')
|
||||
box_user_id=$(id -u ${box_user})
|
||||
box_group_id=$(id -g ${box_group})
|
||||
# Check if box_user and box_group exist
|
||||
[ ${box_user_id} ] && [ ${box_group_id} ] || ( log error "${box_user_group} error, use root:net_admin instead." && box_user_group="root:net_admin" )
|
||||
bin_path=$(which ${bin_name})
|
||||
# Set ownership and permission of kernel directory
|
||||
chown ${box_user_group} ${bin_path}
|
||||
chmod 0700 ${bin_path}
|
||||
chmod 0644 "${data_dir}/${bin_name}"/*
|
||||
# Check if user is not root and group is not net_admin
|
||||
if [ "${box_user_id}" != "0" ] || [ "${box_group_id}" != "3005" ]; then
|
||||
# Set capability of kernel directory
|
||||
setcap 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' ${bin_path} || (box_user_group="root:net_admin" && log error "setcap authorization failed, you may need libcap package.")
|
||||
fi
|
||||
# Set ownership of data directory
|
||||
chown -R ${box_user_group} ${data_dir}
|
||||
log info "Using kernel directory ${bin_name} in ${bin_path}."
|
||||
elif [ -f ${bin_path} ]; then
|
||||
# Set ownership and permission of kernel directory
|
||||
chown ${box_user_group} ${bin_path}
|
||||
chmod 6755 ${bin_path}
|
||||
chmod 644 "${data_dir}/${bin_name}"/*
|
||||
chmod 0700 ${bin_path}
|
||||
chmod 0644 "${data_dir}/${bin_name}"/*
|
||||
# Set ownership of data directory
|
||||
chown -R ${box_user_group} ${data_dir}
|
||||
log info "use the kernel located in '${bin_path}'"
|
||||
log info "Use the kernel located in '${bin_path}'."
|
||||
else
|
||||
if which ${bin_name} | grep -q "/system/bin/" ; then
|
||||
box_user=$(echo ${box_user_group} | busybox awk -F ':' '{print $1}')
|
||||
box_group=$(echo ${box_user_group} | busybox awk -F ':' '{print $2}')
|
||||
box_user_id=$(id -u ${box_user})
|
||||
box_group_id=$(id -g ${box_group})
|
||||
# Check if box_user and box_group exist
|
||||
if [ ${box_user_id} ] && [ ${box_group_id} ]; then
|
||||
bin_path=$(which ${bin_name})
|
||||
# Set ownership and permission of kernel directory
|
||||
chown ${box_user_group} ${bin_path}
|
||||
chmod 6755 ${bin_path}
|
||||
chmod 644 "${data_dir}/${bin_name}"/*
|
||||
# Check if user is not root and group is not net_admin
|
||||
if [ "${box_user_id}" != "0" ] || [ "${box_group_id}" != "3005" ]; then
|
||||
# Set capability of kernel directory
|
||||
if command -v setcap > /dev/null; then
|
||||
setcap 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' ${bin_path} || (box_user_group="root:net_admin" && log error "setcap authorization failed, you may need libcap package.")
|
||||
else
|
||||
box_user_group="root:net_admin"
|
||||
log warn "setcap authorization failed, you may need libcap package. Using root:net_admin instead."
|
||||
fi
|
||||
fi
|
||||
# Set ownership of data directory
|
||||
chown -R ${box_user_group} ${data_dir}
|
||||
log info "Using kernel directory ${bin_name} in ${bin_path}"
|
||||
else
|
||||
bin_path=$(which ${bin_name})
|
||||
box_user_group="root:net_admin"
|
||||
log warn "${box_user_group} error. Using root:net_admin instead."
|
||||
# Set ownership and permission of kernel directory
|
||||
chown ${box_user_group} ${bin_path}
|
||||
chmod 6755 ${bin_path}
|
||||
chmod 644 "${data_dir}/${bin_name}"/*
|
||||
# Set ownership of data directory
|
||||
chown -R ${box_user_group} ${data_dir}
|
||||
log info "use the kernel located in '${bin_path}'"
|
||||
fi
|
||||
else
|
||||
log error "Kernel '${bin_name}' is missing."
|
||||
log error "Please download the '${bin_name}' kernel, place it in the /data/adb/modules/box_for_root/system/bin/ directory and reboot."
|
||||
exit 1
|
||||
fi
|
||||
log error "Kernel '${bin_name}' is missing."
|
||||
log error "Please download the '${bin_name}' kernel and place it in the ${bin_kernel}/ directory."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -146,11 +124,14 @@ check_in_bin() {
|
||||
|
||||
create_tun() {
|
||||
# Enable IP forwarding
|
||||
sysctl net.ipv4.ip_forward=1 >/dev/null 2>&1
|
||||
if ! sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1; then
|
||||
log warn "Cannot enable IP forwarding."
|
||||
fi
|
||||
|
||||
# Creates a symlink for /dev/tun if it doesn't already exist
|
||||
if [ ! -c "/dev/net/tun" ]; then
|
||||
if ! mkdir -p /dev/net; then
|
||||
log warn "Cannot create directory /dev/net" >&2
|
||||
log warn "Cannot create directory /dev/net."
|
||||
exit 1
|
||||
fi
|
||||
if ! mknod /dev/net/tun c 10 200; then
|
||||
@@ -163,44 +144,64 @@ create_tun() {
|
||||
fi
|
||||
}
|
||||
|
||||
default_tproxy() {
|
||||
# set network_mode variable value to "tproxy"
|
||||
sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
|
||||
}
|
||||
|
||||
prepare_singbox() {
|
||||
if [ "${network_mode}" = "mixed" ] || [ "${proxy_mode}" = "tun" ]; then
|
||||
# Reads the enable value from the tun configuration
|
||||
# singbox_tun=$(find /data/adb/box/sing-box/ -name "*.json" -exec busybox awk -F':' '/"type":[[:space:]]*"tun"/{gsub(/^[[:space:]]+|[",[:space:]]+$/,"",$2); print $2}' {} \; | tr -d '"')
|
||||
|
||||
if [[ "${network_mode}" == "mixed" || "${proxy_mode}" == "tun" ]]; then
|
||||
sed -i 's/"auto_detect_interface": false/"auto_detect_interface": true/g' "${data_dir}/sing-box/"*.json
|
||||
sed -i 's/auto_route\": false/auto_route\": true/g' "${data_dir}/sing-box/"*.json
|
||||
sed -i 's/auto_route": false/auto_route": true/g' "${data_dir}/sing-box/"*.json
|
||||
else
|
||||
sed -i 's/"auto_detect_interface": true/"auto_detect_interface": false/g' "${data_dir}/sing-box/"*.json
|
||||
sed -i 's/auto_route\": true/auto_route\": false/g' "${data_dir}/sing-box/"*.json
|
||||
sed -i 's/auto_route": true/auto_route": false/g' "${data_dir}/sing-box/"*.json
|
||||
fi
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
prepare_clash() {
|
||||
ipv6=$(busybox awk '/ipv6:/ { print $2; found=1; exit } END{ if(!found) print "false" }' "${clash_config}" | head -n 1 2>/dev/null)
|
||||
sed -i "s/ipv6=.*/ipv6=\"${ipv6}\"/g" /data/adb/box/settings.ini
|
||||
sed -i "s/ipv6=.*/ipv6=\"${ipv6}\"/g" "${settings}"
|
||||
|
||||
clash_external_ui=$(busybox awk '/external-ui: /{print $1}' "${clash_config}")
|
||||
[ -z "${clash_external_ui}" ] && printf "\nexternal-ui: ./dashboard/dist" >> "${clash_config}"
|
||||
if [ -z "${clash_external_ui}" ]; then
|
||||
echo -e "\nexternal-ui: ./dashboard/dist" >> "${clash_config}"
|
||||
fi
|
||||
|
||||
clash_tproxy_port=$(busybox awk '/tproxy-port: /{print $1}' "${clash_config}")
|
||||
[ -z "${clash_tproxy_port}" ] && printf "\ntproxy-port: ${tproxy_port}" >> "${clash_config}"
|
||||
if [ -z "${clash_tproxy_port}" ]; then
|
||||
echo -e "\ntproxy-port: ${tproxy_port}" >> "${clash_config}"
|
||||
fi
|
||||
|
||||
clash_redir_port=$(busybox awk '/redir-port: /{print $1}' "${clash_config}")
|
||||
[ -z "${clash_redir_port}" ] && printf "\nredir-port: ${redir_port}" >> "${clash_config}"
|
||||
if [ -z "${clash_redir_port}" ]; then
|
||||
echo -e "\nredir-port: ${redir_port}" >> "${clash_config}"
|
||||
fi
|
||||
|
||||
if [ "${network_mode}" = "mixed" ] || [ "${proxy_mode}" = "tun" ]; then
|
||||
clash_tun_status=$(busybox awk -F ': ' '/^tun: *$/{getline; print $2}' "${clash_config}")
|
||||
if [ -z "${clash_tun_status}" ]; then
|
||||
echo -e "\n
|
||||
tun:
|
||||
enable: true
|
||||
mtu: 9000
|
||||
device: utun
|
||||
stack: system # gvisor / system
|
||||
dns-hijack:
|
||||
- any:53
|
||||
auto-route: true
|
||||
auto-detect-interface: true
|
||||
" >> "${clash_config}"
|
||||
fi
|
||||
sed -i "/tun:/ {n;s/enable: false/enable: true/}" "${clash_config}"
|
||||
else
|
||||
sed -i "/tun:/ {n;s/enable: true/enable: false/}" "${clash_config}"
|
||||
fi
|
||||
|
||||
# Reads the enable value from the tun configuration
|
||||
clash_tun_status=$(busybox awk -F ': ' '/^tun: *$/{getline; print $2}' "${clash_config}")
|
||||
if [ "${clash_tun_status}" != "true" ]; then
|
||||
sed -i -E "s/(tproxy-port: )[0-9]+/\1${tproxy_port}/" "${clash_config}"
|
||||
default_tproxy
|
||||
else
|
||||
sed -i -E "s/(network_mode=)\"[^\"]+\"/\1\"mixed\"/" "${settings}"
|
||||
fi
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
prepare_xvray() {
|
||||
if [ ! -f "${data_dir}/${bin_name}"/*.json ]; then
|
||||
log error "file ${data_dir}/${bin_name}/*.json not found"
|
||||
exit 1
|
||||
[ "${proxy_mode}" != "tun" ] && sed -i 's/network_mode=.*/network_mode="mixed"/g' "${settings}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -212,7 +213,7 @@ run_box() {
|
||||
sing-box)
|
||||
prepare_singbox
|
||||
if ${bin_path} check -D "${data_dir}/${bin_name}" --config-directory "${data_dir}/sing-box" > "${run_path}/${bin_name}-report.log" 2>&1 ; then
|
||||
nohup busybox setuidgid 0:3005 ${bin_path} run -D "${data_dir}/${bin_name}" --config-directory "${data_dir}/sing-box" > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
nohup busybox setuidgid ${box_user_group} ${bin_path} run -D "${data_dir}/${bin_name}" --config-directory "${data_dir}/sing-box" > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
echo -n $! > "${pid_file}"
|
||||
else
|
||||
log error "Configuration failed, please check the ${run_path}/${bin_name}-report.log file."
|
||||
@@ -225,7 +226,7 @@ run_box() {
|
||||
clash)
|
||||
prepare_clash
|
||||
if ${bin_path} -t -d "${data_dir}/${bin_name}" -f "${clash_config}" > "${run_path}/${bin_name}-report.log" 2>&1; then
|
||||
nohup busybox setuidgid 0:3005 ${bin_path} -d "${data_dir}/${bin_name}" -f "${clash_config}" > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
nohup busybox setuidgid ${box_user_group} ${bin_path} -d "${data_dir}/${bin_name}" -f "${clash_config}" > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
echo -n $! > "${pid_file}"
|
||||
else
|
||||
log error "configuration failed, please check the ${run_path}/${bin_name}-report.log file."
|
||||
@@ -235,12 +236,16 @@ run_box() {
|
||||
fi
|
||||
;;
|
||||
xray)
|
||||
default_tproxy
|
||||
prepare_xvray
|
||||
# set network_mode variable value to "tproxy"
|
||||
sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
|
||||
if [ ! -f "${data_dir}/${bin_name}"/*.json ]; then
|
||||
log error "file ${data_dir}/${bin_name}/*.json not found"
|
||||
exit 1
|
||||
fi
|
||||
export XRAY_LOCATION_ASSET="${data_dir}/${bin_name}"
|
||||
export XRAY_LOCATION_CONFDIR="${data_dir}/${bin_name}"
|
||||
if ${bin_path} -test > "${run_path}/${bin_name}-report.log" 2>&1; then
|
||||
nohup busybox setuidgid 0:3005 ${bin_path} > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
nohup busybox setuidgid ${box_user_group} ${bin_path} > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
echo -n $! > "${pid_file}"
|
||||
else
|
||||
log error "configuration failed, please check the ${run_path}/${bin_name}-report.log file."
|
||||
@@ -250,12 +255,16 @@ run_box() {
|
||||
fi
|
||||
;;
|
||||
v2fly)
|
||||
default_tproxy
|
||||
prepare_xvray
|
||||
# set network_mode variable value to "tproxy"
|
||||
sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
|
||||
if [ ! -f "${data_dir}/${bin_name}"/*.json ]; then
|
||||
log error "file ${data_dir}/${bin_name}/*.json not found"
|
||||
exit 1
|
||||
fi
|
||||
export V2RAY_LOCATION_ASSET="${data_dir}/${bin_name}"
|
||||
export V2RAY_LOCATION_CONFDIR="${data_dir}/${bin_name}"
|
||||
if (${bin_path} test > "${run_path}/${bin_name}-report.log" 2>&1) ; then
|
||||
nohup busybox setuidgid 0:3005 ${bin_path} run > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
nohup busybox setuidgid ${box_user_group} ${bin_path} run > "${run_path}/${bin_name}.log" 2>&1 &
|
||||
echo -n $! > ${pid_file}
|
||||
else
|
||||
log error "configuration failed, please check the ${run_path}/${bin_name}-report.log file."
|
||||
@@ -287,40 +296,50 @@ fi
|
||||
}
|
||||
|
||||
# Function to display the usage of a binary
|
||||
# This script retrieves information about a running binary process and logs it to a log file.
|
||||
|
||||
bin_usage() {
|
||||
# Get the process ID of the binary
|
||||
bin_pid=$(busybox pidof ${bin_name})
|
||||
|
||||
if [ -z "${bin_pid}" ]; then
|
||||
log error "${bin_name} is not running"
|
||||
log error "${bin_name} is not running."
|
||||
return
|
||||
fi
|
||||
|
||||
# Get the memory usage of the binary
|
||||
rss=$(grep VmRSS /proc/${bin_pid}/status | busybox awk '{print $2}')
|
||||
rss=$(grep VmRSS /proc/${bin_pid}/status | busybox awk '{ print $2 }')
|
||||
[ "${rss}" -ge 1024 ] && bin_rss="$(expr ${rss} / 1024) MB" || bin_rss="${rss} KB"
|
||||
swap=$(grep VmSwap /proc/${bin_pid}/status | busybox awk '{print $2}')
|
||||
swap=$(grep VmSwap /proc/${bin_pid}/status | busybox awk '{ print $2 }')
|
||||
[ "${swap}" -ge 1024 ] && bin_swap="$(expr ${swap} / 1024) MB" || bin_swap="${swap} KB"
|
||||
|
||||
# Get the state of the binary
|
||||
state=$(grep State /proc/${bin_pid}/status | busybox awk '{print $2}')
|
||||
state=$(grep State /proc/${bin_pid}/status | busybox awk '{ print $2" "$3 }')
|
||||
|
||||
# Get the user and group of the binary
|
||||
user_group=$(stat -c %U:%G /proc/${bin_pid})
|
||||
|
||||
# Log the information
|
||||
log info "${bin_name} has started with the '${user_group}' user group."
|
||||
log info "${bin_name} status: ${state}, (PID: ${bin_pid})"
|
||||
log info "${bin_name} status: ${state} (PID: ${bin_pid})"
|
||||
log info "${bin_name} memory usage: ${bin_rss}, swap: ${bin_swap}"
|
||||
|
||||
# Get the CPU usage of the binary
|
||||
cpu=$(ps -p ${bin_pid} -o pcpu | busybox awk 'NR==2{print $1}' 2> /dev/null)
|
||||
cpu=$(ps -p ${bin_pid} -o %cpu | busybox awk 'NR==2{print $1}' 2> /dev/null)
|
||||
if [ -n "${cpu}" ]; then
|
||||
log info "${bin_name} cpu usage: ${cpu}%"
|
||||
log info "${bin_name} CPU usage: ${cpu}%"
|
||||
else
|
||||
log info "${bin_name} cpu usage: not available"
|
||||
log info "${bin_name} CPU usage: not available"
|
||||
fi
|
||||
|
||||
# Get the running time of the binary
|
||||
running_time=$(ps -p ${bin_pid} -o etime | busybox awk 'NR==2{print $1}' 2> /dev/null)
|
||||
if [ -n "${running_time}" ]; then
|
||||
log info "${bin_name} running time: ${running_time} seconds"
|
||||
log info "${bin_name} running time: ${running_time}"
|
||||
else
|
||||
log info "${bin_name} running time: not available"
|
||||
fi
|
||||
|
||||
# Save the process ID to the pid file
|
||||
echo -n "${bin_pid}" > "${pid_file}"
|
||||
}
|
||||
@@ -368,13 +387,14 @@ crontab_alive() {
|
||||
}
|
||||
|
||||
start_box() {
|
||||
# Cleared the log file and added the timestamp and delimiter
|
||||
# Clear the log file and add the timestamp and delimiter
|
||||
echo -n "" > "${logs_file}"
|
||||
# command command -v to check whether busybox is installed or not on your system.
|
||||
# Check whether busybox is installed or not on the system using command -v
|
||||
if ! command -v busybox &> /dev/null; then
|
||||
log error "busybox command not found"
|
||||
log error "BusyBox command not found"
|
||||
exit 1
|
||||
fi
|
||||
# Check if the script is being run in interactive mode or not and display the appropriate message
|
||||
if [ -t 1 ]; then
|
||||
echo -e "\033[1;31m$(date)\033[0m"
|
||||
echo -e "\033[1;32m--------------------------------------------\033[0m"
|
||||
@@ -386,7 +406,7 @@ start_box() {
|
||||
if bin_pid=$(busybox pidof "${bin_name}"); then
|
||||
log info "${bin_name} service is still running, refreshing iptables"
|
||||
if "${scripts_dir}/box.iptables" renew; then
|
||||
log info "iptables refreshed successfully"
|
||||
log info "iptables is refreshed successfully"
|
||||
exit 1
|
||||
else
|
||||
log error "failed to refresh iptables"
|
||||
@@ -398,23 +418,21 @@ start_box() {
|
||||
*) log error "bin_name: '${bin_name}<unknown>' not defined"; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
# Checked permissions, checked for bin existence, deleted old logs, created a TUN, ran box, and waited for 1 second
|
||||
# Executes the check_permission,check_in_bin & delete_logs function
|
||||
# Check permissions, check for bin existence, delete old logs, create a TUN if necessary, run box, and wait for 1 second
|
||||
check_permission
|
||||
check_in_bin
|
||||
delete_logs
|
||||
if [ "${network_mode}" = "mixed" ] || [ "${proxy_mode}" = "tun" ]; then
|
||||
# Executes the create_tun function
|
||||
if [[ "${network_mode}" == "mixed" || "${proxy_mode}" == "tun" ]]; then
|
||||
create_tun
|
||||
fi
|
||||
run_box && sleep 1
|
||||
# Executes crontab_alive if crontab_sec is not equal to "false"
|
||||
# Execute crontab_alive if crontab_sec is not equal to "false"
|
||||
if [ "${crontab_sec}" != "false" ]; then
|
||||
crontab_alive
|
||||
else
|
||||
log info "crontab: disabled."
|
||||
fi
|
||||
# Executes the cgroup limit, detected_port, still_alive, display_bin_pid function
|
||||
# Execute the cgroup_limit, display_bin_pid, detected_port, still_alive functions
|
||||
cgroup_limit
|
||||
detected_port
|
||||
still_alive
|
||||
@@ -422,35 +440,43 @@ start_box() {
|
||||
}
|
||||
|
||||
stop_box() {
|
||||
# Use `pgrep` command to find cronjob PID
|
||||
# Find cronjob PID using `pgrep`
|
||||
cronkill=$(pgrep -f "crond -c ${run_path}")
|
||||
for cron in ${cronkill[@]}; do
|
||||
kill -15 "${cron}"
|
||||
done
|
||||
# Using a loop to kill each binary
|
||||
# Kill each binary using a loop
|
||||
for bin in ${bin_list[@]}; do
|
||||
# Use `busybox pkill` to kill the binary with signal 15
|
||||
busybox pkill -15 "${bin}" || killall -15 "${bin}"
|
||||
# Use `busybox pkill` to kill the binary with signal 15, otherwise use `killall`.
|
||||
if busybox pkill -15 "${bin}"; then
|
||||
: # Do nothing if busybox pkill is successful
|
||||
else
|
||||
killall -15 "${bin}" || true
|
||||
fi
|
||||
done
|
||||
sleep 1
|
||||
# Check if the binary has stopped
|
||||
if ! busybox pidof ${bin_name} >/dev/null 2>&1; then
|
||||
if ! busybox pidof "${bin_name}" >/dev/null 2>&1; then
|
||||
# Delete the `box.pid` file if it exists
|
||||
if [ -f ${run_path}/box.pid ]; then
|
||||
if [ -f "${pid_file}" ]; then
|
||||
rm -f "${pid_file}"
|
||||
sleep 0.5
|
||||
fi
|
||||
display_bin_pid || log warn "${bin_name} disconnected."
|
||||
else
|
||||
log error "failed to stop ${bin_name}"
|
||||
log warn "force stop ${bin_name}."
|
||||
log error "Failed to stop ${bin_name}"
|
||||
log warn "Force stop ${bin_name}."
|
||||
for bin in "${bin_list[@]}"; do
|
||||
# Use `busybox pkill` to kill the binary with signal 9
|
||||
busybox pkill -9 "${bin}" >/dev/null 2>&1 || killall -9 "${bin}" >/dev/null 2>&1
|
||||
# Use `busybox pkill` to kill the binary with signal 9, otherwise use `killall`.
|
||||
if busybox pkill -9 "${bin}"; then
|
||||
: # Do nothing if busybox pkill is successful
|
||||
else
|
||||
killall -9 "${bin}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
sleep 0.5
|
||||
# Check whether the binary has stopped
|
||||
if ! busybox pidof ${bin_name} >/dev/null 2>&1; then
|
||||
if ! busybox pidof "${bin_name}" >/dev/null 2>&1; then
|
||||
log warn "done"
|
||||
fi
|
||||
fi
|
||||
@@ -476,8 +502,13 @@ case "$1" in
|
||||
clash) log debug "$(${bin_path} -v)";;
|
||||
*) log debug "$(${bin_path} version)";;
|
||||
esac
|
||||
[ $(busybox pidof ${bin_name}) ] && \
|
||||
bin_usage || log warn "${bin_name} service is stopped"
|
||||
|
||||
# Memeriksa apakah layanan sudah berjalan atau belum
|
||||
if [ $(busybox pidof ${bin_name}) ]; then
|
||||
bin_usage
|
||||
else
|
||||
log warn "${bin_name} service is stopped"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "$0: usage: $0 {start|stop|restart|usage}"
|
||||
|
||||
@@ -5,58 +5,54 @@ scripts_dir=$(dirname ${scripts})
|
||||
source /data/adb/box/settings.ini
|
||||
|
||||
user_agent="box_for_root"
|
||||
meta=true # option to download Clash kernel clash-premium{false} or clash-meta{true}
|
||||
dev=true # for clash-premium,
|
||||
singbox_releases=false # option to download Singbox kernel beta or release
|
||||
|
||||
# log on terminal
|
||||
logs() {
|
||||
now=$(date +"%I.%M %P")
|
||||
if [ -t 1 ]; then
|
||||
case $1 in
|
||||
info) echo -n "\033[1;34m${now} [info]: $2\033[0m";;
|
||||
port) echo -n "\033[1;33m$2 \033[0m";;
|
||||
testing) echo -n "\033[1;34m$2\033[0m";;
|
||||
success) echo -n "\033[1;32m$2 \033[0m";;
|
||||
failed) echo -n "\033[1;31m$2 \033[0m";;
|
||||
*) echo -n "\033[1;35m${now} [$1]: $2\033[0m";;
|
||||
esac
|
||||
else
|
||||
case $1 in
|
||||
info) echo -n "${now} [info]: $2" | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
port) echo -n "$2 " | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
testing) echo -n "$2" | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
success) echo -n "$2 " | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
failed) echo -n "$2 " | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
*) echo -n "${now} [$1]: $2" | tee -a ${logs_file} >> /dev/null 2>&1;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
# option to download Clash kernel clash-premium{false} or clash-meta{true}
|
||||
meta="true"
|
||||
# for clash-premium
|
||||
dev=true
|
||||
# option to download Singbox kernel beta or release
|
||||
singbox_releases=false
|
||||
|
||||
# Check internet connection with mlbox
|
||||
testing() {
|
||||
# check DNS
|
||||
logs info "dns="
|
||||
for network in $(${data_dir}/bin/mlbox -timeout=5 -dns="-qtype=A -domain=asia.pool.ntp.org" | grep -v 'timeout' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}'); do
|
||||
ntpip=${network}
|
||||
break
|
||||
done
|
||||
[ ! -z "${ntpip}" ] && logs success "done" || logs failed "failed"
|
||||
# check HTTP
|
||||
if [ -n "${ntpip}" ]; then
|
||||
logs testing "http="
|
||||
httpIP=$(busybox wget -qO- http://182.254.116.116/d?dn=reddit.com\&clientip=1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)
|
||||
[ -n "${httpIP}" ] && ( httpIP="${httpIP#*\|}"; logs success "done" ) || logs failed "failed"
|
||||
# check HTTPS
|
||||
logs testing "https="
|
||||
httpsResp=$(busybox wget -qO- --timeout=5 "https://api.infoip.io" 2>&1 | grep -Ev 'timeout|httpGetResponse' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}')
|
||||
[ -n "${httpsResp}" ] && logs success "done" || logs failed "failed"
|
||||
# check UDP
|
||||
logs testing "udp="
|
||||
currentTime=$(${data_dir}/bin/mlbox -timeout=7 -ntp="${ntpip}" | grep -v 'timeout')
|
||||
echo "${currentTime}" | grep -qi 'LI:' && logs success "done" || logs failed "failed"
|
||||
check_connection_with_mlbox() {
|
||||
now=$(date +"%R")
|
||||
connect="\033[1;32mconnect\033[0m"
|
||||
failed="\033[1;33mfailed\033[0m"
|
||||
|
||||
# Check DNS
|
||||
echo -n "\033[1;34m${now} [info]: dns=\033[0m"
|
||||
ntpip=$(${data_dir}/bin/mlbox -timeout=5 -dns="-qtype=A -domain=asia.pool.ntp.org" | grep -v 'timeout' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}' | head -n 1)
|
||||
if [ -z "${ntpip}" ]; then
|
||||
echo "$failed"
|
||||
else
|
||||
echo "$connect"
|
||||
|
||||
# Check HTTP
|
||||
echo -n "\033[1;34m${now} [info]: http=\033[0m"
|
||||
httpIP=$(busybox wget -qO- "http://182.254.116.116/d?dn=reddit.com&clientip=1" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 | cut -d "|" -f 2)
|
||||
if [ -z "${httpIP}" ]; then
|
||||
echo "$failed"
|
||||
else
|
||||
echo "$connect"
|
||||
|
||||
# Check HTTPS
|
||||
echo -n "\033[1;34m${now} [info]: https=\033[0m"
|
||||
httpsResp=$(${data_dir}/bin/mlbox -timeout=5 -http="https://api.infoip.io" 2>&1 | grep -Ev 'timeout|httpGetResponse' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}')
|
||||
if [ -z "${httpsResp}" ]; then
|
||||
echo "$failed"
|
||||
else
|
||||
echo "$connect"
|
||||
|
||||
# Check UDP
|
||||
echo -n "\033[1;34m${now} [info]: udp=\033[0m"
|
||||
currentTime=$(${data_dir}/bin/mlbox -timeout=7 -ntp="${ntpip}" | grep -v 'timeout')
|
||||
if echo "${currentTime}" | grep -qi 'LI:'; then
|
||||
echo "$connect"
|
||||
else
|
||||
echo "$failed"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ -t 1 ] && echo -e "\033[1;31m\033[0m" || echo "" | tee -a ${logs_file} >> /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Check if a binary is running by checking the pid file
|
||||
@@ -149,12 +145,12 @@ update_subgeo() {
|
||||
;;
|
||||
esac
|
||||
if [ "${auto_update_geox}" = "true" ] && log debug "Downloading ${geoip_url}" && update_file "${geoip_file}" "${geoip_url}" && log debug "Downloading ${geosite_url}" && update_file "${geosite_file}" "${geosite_url}"; then
|
||||
log debug "Update geo $(date +"%Y-%m-%d %I.%M %p")"
|
||||
log debug "Update geo $(date +"%F %R")"
|
||||
flag=false
|
||||
fi
|
||||
if [ "${bin_name}" = "clash" ] && [ "${auto_update_subscription}" = "true" ] && update_file "${clash_config}" "${subscription_url}"; then
|
||||
flag=true
|
||||
log debug "Downloading ${clash_config}"
|
||||
flag=true
|
||||
fi
|
||||
if [ -f "${pid_file}" ] && [ "${flag}" = "true" ]; then
|
||||
restart_box
|
||||
@@ -163,32 +159,39 @@ update_subgeo() {
|
||||
|
||||
# Function for detecting ports used by a process
|
||||
port_detection() {
|
||||
# Use 'command' function to check if 'ss' is available
|
||||
# Gunakan fungsi 'command' untuk memeriksa ketersediaan 'ss'
|
||||
if command -v ss > /dev/null ; then
|
||||
# Use 'awk' with a regular expression to match the process ID
|
||||
# Gunakan 'awk' dengan regular expression untuk mencocokkan ID proses
|
||||
ports=$(ss -antup | busybox awk -v pid="$(busybox pidof "${bin_name}")" '$7 ~ pid {print $5}' | busybox awk -F ':' '{print $2}' | sort -u)
|
||||
else
|
||||
# Log a warning message if 'ss' is not available
|
||||
# Catat pesan peringatan jika 'ss' tidak tersedia
|
||||
log debug "ss command not found, skipping port detection." >&2
|
||||
return
|
||||
fi
|
||||
# Log the detected ports
|
||||
logs debug "${bin_name} port detected: "
|
||||
while read -r port ; do
|
||||
sleep 0.5
|
||||
logs port "${port}"
|
||||
done <<< "${ports}"
|
||||
# Add a newline to the output if running in a terminal
|
||||
[ -t 1 ] && echo -e "\033[1;31m""\033[0m" || echo "" >> "${logs_file}" 2>&1
|
||||
}
|
||||
|
||||
# kill bin
|
||||
kill_alive() {
|
||||
for list in "${bin_list[@]}" ; do
|
||||
if busybox pidof "${list}" >/dev/null ; then
|
||||
busybox pkill -15 "${list}" >/dev/null 2>&1 || killall -15 "${list}" >/dev/null 2>&1
|
||||
# Catat port yang terdeteksi
|
||||
now=$(date +"%R")
|
||||
if [ -t 1 ]; then
|
||||
echo -n "\033[1;33m${now} [debug]: ${bin_name} port detected: \033[0m"
|
||||
else
|
||||
echo -n "${now} [debug]: ${bin_name} port detected: " | tee -a "${logs_file}" >> /dev/null 2>&1
|
||||
fi
|
||||
|
||||
while read -r port; do
|
||||
sleep 0.5
|
||||
if [ -t 1 ]; then
|
||||
echo -n "\033[1;33m${port} \033[0m"
|
||||
else
|
||||
echo -n "${port} " | tee -a "${logs_file}" >> /dev/null 2>&1
|
||||
fi
|
||||
done
|
||||
done <<< "${ports}"
|
||||
|
||||
# Tambahkan newline pada output jika dijalankan di terminal
|
||||
if [ -t 1 ]; then
|
||||
echo -e "\033[1;31m""\033[0m"
|
||||
else
|
||||
echo "" >> "${logs_file}" 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
update_kernel() {
|
||||
@@ -214,7 +217,6 @@ update_kernel() {
|
||||
download_link="${url_down}/download/${sing_box_version_temp}/sing-box-${sing_box_version}-${platform}-${arch}.tar.gz"
|
||||
log debug "download ${download_link}"
|
||||
update_file "${data_dir}/${file_kernel}.tar.gz" "${download_link}"
|
||||
# [ "$?" = "0" ] && kill_alive > /dev/null 2>&1
|
||||
;;
|
||||
clash)
|
||||
if [ "${meta}" = "true" ]; then
|
||||
@@ -225,7 +227,7 @@ update_kernel() {
|
||||
latest_version=$(busybox wget --no-check-certificate -qO- "${download_link}/expanded_assets/${tag}" | grep -oE "alpha-[0-9a-z]+" | head -1)
|
||||
# set the filename based on platform and architecture
|
||||
filename="clash.meta-${platform}-${arch}"
|
||||
[ $(uname -m) != "aarch64" ] || filename+="-cgo"
|
||||
# [ $(uname -m) != "aarch64" ] || filename+="-cgo"
|
||||
filename+="-${latest_version}"
|
||||
# download and update the file
|
||||
log debug "download ${download_link}/download/${tag}/${filename}.gz"
|
||||
@@ -243,43 +245,24 @@ update_kernel() {
|
||||
update_file "${data_dir}/${file_kernel}.gz" "https://github.com/Dreamacro/clash/releases/download/premium/${filename}.gz"
|
||||
fi
|
||||
fi
|
||||
# if the update_file command was successful, kill the alive process
|
||||
# [ "$?" = "0" ] && kill_alive > /dev/null 2>&1
|
||||
;;
|
||||
xray)
|
||||
xray|v2fly)
|
||||
[ "${bin_name}" = "xray" ] && bin='Xray' || bin='v2ray'
|
||||
api_url="https://api.github.com/repos/$(if [ "${bin_name}" = "xray" ]; then echo "XTLS/Xray-core/releases"; else echo "v2fly/v2ray-core/releases"; fi)"
|
||||
# set download link and get the latest version
|
||||
latest_version=$(busybox wget --no-check-certificate -qO- https://api.github.com/repos/XTLS/Xray-core/releases | grep "tag_name" | grep -o "v[0-9.]*" | head -1)
|
||||
latest_version=$(busybox wget --no-check-certificate -qO- ${api_url} | grep "tag_name" | grep -o "v[0-9.]*" | head -1)
|
||||
case $(uname -m) in
|
||||
"i386") download_file="Xray-linux-32.zip" ;;
|
||||
"x86_64") download_file="Xray-linux-64.zip" ;;
|
||||
"armv7l"|"armv8l") download_file="Xray-linux-arm32-v7a.zip" ;;
|
||||
"aarch64") download_file="Xray-android-arm64-v8a.zip" ;;
|
||||
"i386") download_file="$bin-linux-32.zip" ;;
|
||||
"x86_64") download_file="$bin-linux-64.zip" ;;
|
||||
"armv7l"|"armv8l") download_file="$bin-linux-arm32-v7a.zip" ;;
|
||||
"aarch64") download_file="$bin-android-arm64-v8a.zip" ;;
|
||||
*) log error "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
# Do anything else below
|
||||
download_link="https://github.com/XTLS/Xray-core/releases"
|
||||
download_link="https://github.com/$(if [ "${bin_name}" = "xray" ]; then echo "XTLS/Xray-core/releases"; else echo "v2fly/v2ray-core/releases"; fi)"
|
||||
log debug "Downloading ${download_link}/download/${latest_version}/${download_file}"
|
||||
update_file "${data_dir}/${file_kernel}.zip" "${download_link}/download/${latest_version}/${download_file}"
|
||||
# if the update_file command was successful, kill the alive process
|
||||
# [ "$?" = "0" ] && kill_alive > /dev/null 2>&1
|
||||
;;
|
||||
v2fly)
|
||||
# set download link and get the latest version
|
||||
latest_version=$(busybox wget --no-check-certificate -qO- https://api.github.com/repos/v2fly/v2ray-core/releases | grep "tag_name" | grep -o "v[0-9.]*" | head -1)
|
||||
case $(uname -m) in
|
||||
"i386") download_file="v2ray-linux-32.zip" ;;
|
||||
"x86_64") download_file="v2ray-linux-64.zip" ;;
|
||||
"armv7l"|"armv8l") download_file="v2ray-linux-arm32-v7a.zip" ;;
|
||||
"aarch64") download_file="v2ray-android-arm64-v8a.zip" ;;
|
||||
*) log error "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
# Do anything else below
|
||||
download_link="https://github.com/v2fly/v2ray-core/releases"
|
||||
log debug "Downloading ${download_link}/download/${latest_version}/${download_file}"
|
||||
update_file "${data_dir}/${file_kernel}.zip" "${download_link}/download/${latest_version}/${download_file}"
|
||||
# if the update_file command was successful, kill the alive process
|
||||
# [ "$?" = "0" ] && kill_alive > /dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
log error "kernel error."
|
||||
exit 1
|
||||
@@ -289,33 +272,50 @@ update_kernel() {
|
||||
case "${bin_name}" in
|
||||
clash)
|
||||
gunzip_command=$(command -v gunzip >/dev/null 2>&1 && echo "gunzip" || echo "busybox gunzip")
|
||||
if ${gunzip_command} "${data_dir}/${file_kernel}.gz" >&2 && mv "${data_dir}/${file_kernel}" "${bin_kernel}/${bin_name}"; then
|
||||
[ -f "${pid_file}" ] && restart_box || log debug "${bin_name} does not need to be restarted"
|
||||
if ${gunzip_command} "${data_dir}/${file_kernel}.gz" >&2 &&
|
||||
mv "${data_dir}/${file_kernel}" "${bin_kernel}/${bin_name}"; then
|
||||
if [ -f "${pid_file}" ]; then
|
||||
restart_box
|
||||
else
|
||||
log debug "${bin_name} does not need to be restarted."
|
||||
fi
|
||||
else
|
||||
log error "Failed to extract or move the kernel"
|
||||
log error "Failed to extract or move the kernel."
|
||||
fi
|
||||
;;
|
||||
sing-box)
|
||||
tar_command=$(command -v tar >/dev/null 2>&1 && echo "tar" || echo "busybox tar")
|
||||
if ${tar_command} -xf "${data_dir}/${file_kernel}.tar.gz" -C "${data_dir}/bin" >&2 && mv "${data_dir}/bin/sing-box-${sing_box_version}-${platform}-${arch}/sing-box" "${bin_kernel}/${bin_name}" && rm -r "${data_dir}/bin/sing-box-${sing_box_version}-${platform}-${arch}"; then
|
||||
[ -f "${pid_file}" ] && restart_box || log debug "${bin_name} does not need to be restarted"
|
||||
if ${tar_command} -xf "${data_dir}/${file_kernel}.tar.gz" -C "${data_dir}/bin" >&2 &&
|
||||
mv "${data_dir}/bin/sing-box-${sing_box_version}-${platform}-${arch}/sing-box" "${bin_kernel}/${bin_name}" &&
|
||||
rm -r "${data_dir}/bin/sing-box-${sing_box_version}-${platform}-${arch}"; then
|
||||
if [ -f "${pid_file}" ]; then
|
||||
restart_box
|
||||
else
|
||||
log debug "${bin_name} does not need to be restarted."
|
||||
fi
|
||||
else
|
||||
log warn "failed to extract ${data_dir}/${file_kernel}.tar.gz" && flag="false"
|
||||
log warn "Failed to extract ${data_dir}/${file_kernel}.tar.gz."
|
||||
flag="false"
|
||||
fi
|
||||
;;
|
||||
v2fly|xray)
|
||||
[ "${bin_name}" = "xray" ] && bin='xray' || bin='v2ray'
|
||||
unzip_command=$(command -v unzip >/dev/null 2>&1 && echo "unzip" || echo "busybox unzip")
|
||||
if ${unzip_command} -o "${data_dir}/${file_kernel}.zip" "${bin}" -d "${bin_kernel}" >&2 ; then
|
||||
|
||||
if ${unzip_command} -o "${data_dir}/${file_kernel}.zip" "${bin}" -d "${bin_kernel}" >&2; then
|
||||
if mv "${bin_kernel}/${bin}" "${bin_kernel}/${bin_name}"; then
|
||||
[ -f "${pid_file}" ] && restart_box || log debug "${bin_name} does not need to be restarted"
|
||||
if [ -f "${pid_file}" ]; then
|
||||
restart_box
|
||||
else
|
||||
log debug "${bin_name} does not need to be restarted."
|
||||
fi
|
||||
else
|
||||
log error "failed to move the kernel"
|
||||
log error "Failed to move the kernel."
|
||||
fi
|
||||
else
|
||||
log warn "failed to extract ${data_dir}/${file_kernel}.zip"
|
||||
log warn "Failed to extract ${data_dir}/${file_kernel}.zip."
|
||||
fi
|
||||
;;
|
||||
;;
|
||||
*)
|
||||
log error "kernel error."
|
||||
exit 1
|
||||
@@ -329,23 +329,26 @@ update_kernel() {
|
||||
|
||||
# Function to limit cgroup memory
|
||||
cgroup_limit() {
|
||||
# Check if cgroup_memory_limit is set
|
||||
# Periksa apakah cgroup_memory_limit telah diatur.
|
||||
if [ -z "${cgroup_memory_limit}" ]; then
|
||||
log warn "cgroup_memory_limit is not set"
|
||||
return 1
|
||||
fi
|
||||
# Check if cgroup_memory_path is set and exists
|
||||
|
||||
# Periksa apakah cgroup_memory_path diatur dan ada.
|
||||
if [ -z "${cgroup_memory_path}" ]; then
|
||||
local cgroup_memory_path=$(mount | grep cgroup | busybox awk '/memory/{print $3}' | head -1)
|
||||
|
||||
if [ -z "${cgroup_memory_path}" ]; then
|
||||
log warn "cgroup_memory_path is not set and cannot be found"
|
||||
log warn "cgroup_memory_path is not set and could not be found"
|
||||
return 1
|
||||
fi
|
||||
elif [ ! -d "${cgroup_memory_path}" ]; then
|
||||
log warn "${cgroup_memory_path} does not exist"
|
||||
return 1
|
||||
fi
|
||||
# Check if pid_file is set and exists
|
||||
|
||||
# Periksa apakah pid_file diatur dan ada.
|
||||
if [ -z "${pid_file}" ]; then
|
||||
log warn "pid_file is not set"
|
||||
return 1
|
||||
@@ -353,25 +356,30 @@ cgroup_limit() {
|
||||
log warn "${pid_file} does not exist"
|
||||
return 1
|
||||
fi
|
||||
# Create cgroup directory and move process to cgroup
|
||||
local bin_name=$(basename "$0")
|
||||
|
||||
# Buat direktori cgroup dan pindahkan proses ke cgroup.
|
||||
local bin_name=${bin_name}
|
||||
# local bin_name=$(basename "$0")
|
||||
mkdir -p "${cgroup_memory_path}/${bin_name}"
|
||||
local pid=$(cat "${pid_file}")
|
||||
|
||||
echo "${pid}" > "${cgroup_memory_path}/${bin_name}/cgroup.procs" \
|
||||
&& log info "Moved process ${pid} to ${cgroup_memory_path}/${bin_name}/cgroup.procs"
|
||||
# Set memory limit for cgroup
|
||||
|
||||
# Tetapkan batas memori untuk cgroup.
|
||||
echo "${cgroup_memory_limit}" > "${cgroup_memory_path}/${bin_name}/memory.limit_in_bytes" \
|
||||
&& log info "Set memory limit to ${cgroup_memory_limit} for ${cgroup_memory_path}/${bin_name}/memory.limit_in_bytes"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
update_dashboard() {
|
||||
if [ "${bin_name}" = "sing-box" ] || [ "${bin_name}" = "clash" ]; then
|
||||
if [[ "${bin_name}" == "sing-box" || "${bin_name}" == "clash" ]]; then
|
||||
file_dashboard="${data_dir}/${bin_name}/dashboard.zip"
|
||||
rm -rf "${data_dir}/${bin_name}/dashboard/dist"
|
||||
url="https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip"
|
||||
dir_name="Yacd-meta-gh-pages"
|
||||
busybox wget --no-check-certificate "${url}" -O "${file_dashboard}" 2>&1
|
||||
url="https://github.com/CHIZI-0618/yacd/archive/gh-pages.zip"
|
||||
dir_name="yacd-gh-pages"
|
||||
busybox wget --no-check-certificate "${url}" -O "${file_dashboard}" >&2 || { log error "Failed to download ${url}"; exit 1; }
|
||||
unzip -o "${file_dashboard}" "${dir_name}/*" -d "${data_dir}/${bin_name}/dashboard" >&2
|
||||
mv -f "${data_dir}/${bin_name}/dashboard/${dir_name}" "${data_dir}/${bin_name}/dashboard/dist"
|
||||
rm -f "${file_dashboard}"
|
||||
@@ -410,7 +418,7 @@ reload() {
|
||||
|
||||
case "$1" in
|
||||
testing)
|
||||
testing
|
||||
check_connection_with_mlbox
|
||||
;;
|
||||
keepdns)
|
||||
keep_dns
|
||||
|
||||
@@ -16,14 +16,20 @@ refresh_box() {
|
||||
|
||||
start_service() {
|
||||
if [ ! -f "/data/adb/box/manual" ]; then
|
||||
[ ! -f "${moddir}/disable" ] && "${scripts_dir}/box.service" start >> "/dev/null" 2>&1
|
||||
[ -f "/data/adb/box/run/box.pid" ] && "${scripts_dir}/box.iptables" enable >> "/dev/null" 2>&1
|
||||
if [ ! -f "${moddir}/disable" ]; then
|
||||
"${scripts_dir}/box.service" start >> "/dev/null" 2>&1
|
||||
fi
|
||||
|
||||
for pid in $(pidof inotifyd) ; do
|
||||
if grep -q box.inotify /proc/${pid}/cmdline ; then
|
||||
if [ -f "/data/adb/box/run/box.pid" ]; then
|
||||
"${scripts_dir}/box.iptables" enable >> "/dev/null" 2>&1
|
||||
fi
|
||||
|
||||
for pid in $(pidof inotifyd); do
|
||||
if grep -q box.inotify /proc/${pid}/cmdline; then
|
||||
kill ${pid}
|
||||
fi
|
||||
done
|
||||
|
||||
inotifyd "${scripts_dir}/box.inotify" "${moddir}" >> "/dev/null" 2>&1 &
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -13,14 +13,13 @@ port_detect="false"
|
||||
# enable/disable IPv6: true / false
|
||||
ipv6="false"
|
||||
# list of available kernel binaries
|
||||
bin_list=("clash" "sing-box" "xray" "v2fly")
|
||||
bin_list=( "clash" "sing-box" "xray" "v2fly" )
|
||||
# select the client to use : clash / sing-box / xray / v2fly
|
||||
bin_name="clash"
|
||||
|
||||
# This script is used to set the user and group for the BFM core files.
|
||||
# If you want to change the user or group, make sure the BFM core files are located in the /system/bin directory, otherwise the changes will not take effect.
|
||||
# If you are using Magisk, you can copy the BFM core files (sing-box, clash, etc.) to /data/adb/modules/box_for_root/system/bin/ and reboot the phone.
|
||||
# box_user_group="bin:system"
|
||||
box_user_group="root:net_admin"
|
||||
|
||||
# redirect: tcp only, / tproxy: for tcp+udp with tproxy, / mixed: mode with redirect[tcp] and tun[udp]
|
||||
@@ -37,7 +36,7 @@ ap_list=( "softap+" "wlan+" "swlan+" "ap+" "rndis+" )
|
||||
ignore_out_list=()
|
||||
|
||||
# Set update interval using cron, for more information: https://crontab.guru/
|
||||
crontab_sec='false'
|
||||
crontab_sec="false"
|
||||
update_interval="0 12 */3 * *" # updates will run at 12 noon every three days.
|
||||
# Update sub&geo
|
||||
# Type "su -c /data/adb/box/scripts/box.tool subgeo" to update
|
||||
@@ -62,29 +61,34 @@ scripts_dir="${data_dir}/scripts"
|
||||
system_packages_file="/data/system/packages.list"
|
||||
uid_list=("/data/adb/box/run/appuid.list")
|
||||
|
||||
# config clash
|
||||
# konfigurasi clash
|
||||
name_clash_config="config.yaml"
|
||||
clash_config="${data_dir}/clash/${name_clash_config}"
|
||||
|
||||
# Set DNS variables, doc dns https://adguard-dns.io/kb/general/dns-providers/
|
||||
intervaldns=""
|
||||
# intervaldns="*/10 * * * *" #
|
||||
# Mengatur variabel DNS, dokumentasi DNS ada di https://adguard-dns.io/kb/general/dns-providers/.
|
||||
# Variabel intervaldns harus dalam format cron. Misalnya "*/10 * * * *" untuk menjalankannya setiap 10 menit.
|
||||
# Jika tidak ada jadwal yang ingin diatur, intervaldns harus dikosongkan.
|
||||
intervaldns="*/10 * * * *"
|
||||
static_dns1="94.140.14.14"
|
||||
static_dns2="2a10:50c0::ad1:ff"
|
||||
|
||||
log() {
|
||||
# Get the current time
|
||||
now=$(date +"%I.%M %P")
|
||||
case $1 in
|
||||
info) color="\033[1;34m" ;; # print the log message in blue
|
||||
error) color="\033[1;31m" ;; # print the log message in red
|
||||
warn) color="\033[1;33m" ;; # print the log message in yellow
|
||||
*) color="\033[1;32m" ;; # print the log message in magenta
|
||||
esac
|
||||
message="${now} [$1]: $2"
|
||||
if [ -t 1 ]; then
|
||||
echo -e "${color}${message}\033[0m"
|
||||
else
|
||||
echo "${message}" | tee -a ${logs_file} >> /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
# Mengambil waktu saat ini
|
||||
now=$(date +"%R")
|
||||
# Memilih warna teks sesuai parameter
|
||||
case $1 in
|
||||
info) color="\033[1;34m" ;; # untuk pesan info, tulisan warna biru
|
||||
error) color="\033[1;31m" ;; # untuk pesan error, tulisan warna merah
|
||||
warn) color="\033[1;33m" ;; # untuk pesan warn, tulisan warna kuning
|
||||
*) color="\033[1;32m" ;; # untuk opsi parameter yang tidak dikenali, tulisan warna magenta
|
||||
esac
|
||||
# Menambah pesan ke waktu dan parameter
|
||||
message="${now} [$1]: $2"
|
||||
if [ -t 1 ]; then
|
||||
# Mencetak pesan ke konsol
|
||||
echo -e "${color}${message}\033[0m"
|
||||
else
|
||||
# Mencetak pesan ke file log
|
||||
echo "${message}" >> ${logs_file} 2>&1
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user