Files

150 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
hostname_value="${TPROXY_HOSTNAME:-}"
public_ip="${MTPROXY_PUBLIC_IP:-}"
workers="${MTPROXY_WORKERS:-1}"
max_connections="${MTPROXY_MAX_CONNECTIONS:-4096}"
if [[ ! "$hostname_value" =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ ]] ||
[[ "$hostname_value" != *.* ]]; then
echo "TPROXY_HOSTNAME must be a lowercase DNS hostname" >&2
exit 2
fi
valid_ipv4() {
local ip=$1 octet
local -a octets
local IFS=.
read -r -a octets <<<"$ip"
[[ ${#octets[@]} -eq 4 ]] || return 1
for octet in "${octets[@]}"; do
[[ "$octet" =~ ^[0-9]{1,3}$ ]] || return 1
((10#$octet <= 255)) || return 1
done
}
if ! valid_ipv4 "$public_ip"; then
echo "MTPROXY_PUBLIC_IP must be a public IPv4 address" >&2
exit 2
fi
if [[ ! "$workers" =~ ^[1-9][0-9]*$ ]] || ((workers > 256)); then
echo "MTPROXY_WORKERS must be between 1 and 256" >&2
exit 2
fi
if [[ ! "$max_connections" =~ ^[1-9][0-9]*$ ]]; then
echo "MTPROXY_MAX_CONNECTIONS must be positive" >&2
exit 2
fi
install -d -o root -g root -m 0700 /data/mtproxy
install -d -o root -g tproxy -m 0750 /data/tproxy /run/tproxy
atomic_download() {
local url=$1 destination=$2 minimum_size=$3 required_pattern=$4 temporary
temporary="${destination}.new"
rm -f "$temporary"
curl --fail --silent --show-error --location \
--proto '=https' --proto-redir '=https' --tlsv1.2 \
--output "$temporary" "$url"
[[ $(wc -c <"$temporary") -ge $minimum_size ]]
grep -q "$required_pattern" "$temporary"
chmod 0600 "$temporary"
mv -f "$temporary" "$destination"
}
atomic_download \
https://core.telegram.org/getProxySecret \
/data/mtproxy/proxy-secret 128 '.'
atomic_download \
https://core.telegram.org/getProxyConfig \
/data/mtproxy/proxy-multi.conf 100 '^proxy_for '
chown root:mtproxy /data/mtproxy/proxy-secret /data/mtproxy/proxy-multi.conf
chmod 0640 /data/mtproxy/proxy-secret /data/mtproxy/proxy-multi.conf
if [[ ! -s /data/client-secret ]]; then
openssl rand -hex 16 > /data/client-secret
fi
client_secret="$(tr -d '\r\n' </data/client-secret)"
if [[ ! "$client_secret" =~ ^[0-9a-f]{32}$ ]]; then
echo "persisted client secret is invalid" >&2
exit 2
fi
chown root:root /data/client-secret
chmod 0600 /data/client-secret
if [[ -e /data/tproxy/token.key ]]; then
chown root:root /data/tproxy/token.key
fi
if [[ ! -s /data/tproxy/token.key ]]; then
head -c 32 /dev/urandom > /data/tproxy/token.key
fi
chmod 0400 /data/tproxy/token.key
chown tproxy:tproxy /data/tproxy/token.key
rm -f /data/tproxy/config.json /run/tproxy/profiles.json
cat > /data/tproxy/config.json <<JSON
{
"public_hostname": "$hostname_value",
"base_path": "",
"listen": "127.0.0.1:8080",
"admin_listen": "127.0.0.1:8081",
"public_dir": "/srv/tproxy-site",
"token_key_file": "/data/tproxy/token.key",
"static_routes": "exact",
"profiles_file": "/run/tproxy/profiles.json",
"enable_pprof": false
}
JSON
cat > /run/tproxy/profiles.json <<JSON
{"profiles":[{"name":"default","secret":"$client_secret","backend":"127.0.0.1:2398","carrier_mode":"websocket"}]}
JSON
chmod 0400 /data/tproxy/config.json /run/tproxy/profiles.json
chown tproxy:tproxy /data/tproxy/config.json /run/tproxy/profiles.json
runuser -u tproxy -- /usr/local/bin/tproxy-server \
-config /data/tproxy/config.json \
-profiles-file /run/tproxy/profiles.json -check
local_ip="$(hostname -I | tr ' ' '\n' | awk '/^[0-9]+\./ {print; exit}')"
if ! valid_ipv4 "$local_ip"; then
echo "could not determine the container IPv4 address" >&2
exit 1
fi
/usr/local/bin/mtproto-proxy \
-u mtproxy \
-p 8888 \
-H 2398 \
-S "$client_secret" \
--nat-info "$local_ip:$public_ip" \
--aes-pwd /data/mtproxy/proxy-secret /data/mtproxy/proxy-multi.conf \
-M "$workers" \
-C "$max_connections" &
mtproxy_pid=$!
runuser -u tproxy -- /usr/local/bin/tproxy-server \
-config /data/tproxy/config.json &
relay_pid=$!
runuser -u tproxy -- env TPROXY_HOSTNAME="$hostname_value" \
/usr/local/bin/tproxy-ingress &
ingress_pid=$!
stop_all() {
trap - EXIT TERM INT
kill -TERM "$ingress_pid" "$relay_pid" "$mtproxy_pid" 2>/dev/null || true
wait "$ingress_pid" "$relay_pid" "$mtproxy_pid" 2>/dev/null || true
}
trap stop_all EXIT TERM INT
set +e
wait -n "$mtproxy_pid" "$relay_pid" "$ingress_pid"
status=$?
set -e
exit "$status"