#!/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' &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 < /run/tproxy/profiles.json <&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"