Changes:
feat: Add SNI checker and certificate manager Key features: - Domain-to-IP resolution verification - Automatic Let's Encrypt certificate acquisition - Self-signed fallback for domains not pointed to the server - Updates insecure flag in config.json based on certificate type - Updates SNI in environment config - Generates and updates SHA-256 fingerprint fix(urls): Update URI generator to respect TLS insecure flag Changes: - Added insecure parameter to generate_uri() function - Read TLS insecure flag from config.json - Set insecure=0 for valid certificates and insecure=1 for self-signed ones - Updated all URI generation calls to include the insecure parameter
This commit is contained in:
@ -1,44 +1,88 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Source the necessary paths
|
|
||||||
source /etc/hysteria/core/scripts/path.sh
|
source /etc/hysteria/core/scripts/path.sh
|
||||||
|
|
||||||
|
sni="$1"
|
||||||
|
|
||||||
|
if [ -f "$CONFIG_ENV" ]; then
|
||||||
|
source "$CONFIG_ENV"
|
||||||
|
else
|
||||||
|
echo "Error: Config file $CONFIG_ENV not found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
update_sni() {
|
update_sni() {
|
||||||
local sni=$1
|
local sni=$1
|
||||||
|
local server_ip
|
||||||
|
|
||||||
if [ -z "$sni" ]; then
|
if [ -z "$sni" ]; then
|
||||||
echo "Invalid SNI. Please provide a valid SNI."
|
echo "Invalid SNI. Please provide a valid SNI."
|
||||||
|
echo "Example: $0 yourdomain.com"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$IP4" ]; then
|
||||||
|
server_ip="$IP4"
|
||||||
|
echo "Using server IP from config: $server_ip"
|
||||||
|
else
|
||||||
|
server_ip=$(curl -s ifconfig.me)
|
||||||
|
echo "Using auto-detected server IP: $server_ip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Checking if $sni points to this server ($server_ip)..."
|
||||||
|
domain_ip=$(dig +short "$sni" A | head -n 1)
|
||||||
|
|
||||||
|
if [ -z "$domain_ip" ]; then
|
||||||
|
echo "Warning: Could not resolve $sni to an IPv4 address."
|
||||||
|
use_certbot=false
|
||||||
|
elif [ "$domain_ip" = "$server_ip" ]; then
|
||||||
|
echo "Success: $sni correctly points to this server ($server_ip)."
|
||||||
|
use_certbot=true
|
||||||
|
else
|
||||||
|
echo "Notice: $sni points to $domain_ip, not to this server ($server_ip)."
|
||||||
|
use_certbot=false
|
||||||
|
fi
|
||||||
|
|
||||||
cd /etc/hysteria/ || exit
|
cd /etc/hysteria/ || exit
|
||||||
|
|
||||||
|
if [ "$use_certbot" = true ]; then
|
||||||
|
echo "Using certbot to obtain a valid certificate for $sni..."
|
||||||
|
|
||||||
|
if certbot certificates | grep -q "$sni"; then
|
||||||
|
echo "Certificate for $sni already exists. Renewing..."
|
||||||
|
certbot renew --cert-name "$sni"
|
||||||
|
else
|
||||||
|
echo "Requesting new certificate for $sni..."
|
||||||
|
certbot certonly --standalone -d "$sni" --non-interactive --agree-tos --email admin@"$sni"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp /etc/letsencrypt/live/"$sni"/fullchain.pem /etc/hysteria/ca.crt
|
||||||
|
cp /etc/letsencrypt/live/"$sni"/privkey.pem /etc/hysteria/ca.key
|
||||||
|
|
||||||
|
echo "Certificates successfully installed from Let's Encrypt."
|
||||||
|
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
jq '.tls.insecure = false' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
|
||||||
|
echo "TLS insecure flag set to false in $CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Using self-signed certificate with openssl for $sni..."
|
||||||
rm -f ca.key ca.crt
|
rm -f ca.key ca.crt
|
||||||
|
|
||||||
echo "Generating CA key and certificate for SNI: $sni ..."
|
echo "Generating CA key and certificate for SNI: $sni ..."
|
||||||
openssl ecparam -genkey -name prime256v1 -out ca.key >/dev/null 2>&1
|
openssl ecparam -genkey -name prime256v1 -out ca.key >/dev/null 2>&1
|
||||||
openssl req -new -x509 -days 36500 -key ca.key -out ca.crt -subj "/CN=$sni" >/dev/null 2>&1
|
openssl req -new -x509 -days 36500 -key ca.key -out ca.crt -subj "/CN=$sni" >/dev/null 2>&1
|
||||||
|
echo "Self-signed certificate generated for $sni"
|
||||||
|
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
jq '.tls.insecure = true' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
|
||||||
|
echo "TLS insecure flag set to true in $CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
chown hysteria:hysteria /etc/hysteria/ca.key /etc/hysteria/ca.crt
|
chown hysteria:hysteria /etc/hysteria/ca.key /etc/hysteria/ca.crt
|
||||||
chmod 640 /etc/hysteria/ca.key /etc/hysteria/ca.crt
|
chmod 640 /etc/hysteria/ca.key /etc/hysteria/ca.crt
|
||||||
|
|
||||||
sha256=$(openssl x509 -noout -fingerprint -sha256 -inform pem -in ca.crt | sed 's/.*=//;s///g')
|
sha256=$(openssl x509 -noout -fingerprint -sha256 -inform pem -in ca.crt | sed 's/.*=//;s///g')
|
||||||
|
|
||||||
# sha256=$(python3 - <<EOF
|
|
||||||
# import base64
|
|
||||||
# import binascii
|
|
||||||
|
|
||||||
# # Hexadecimal string
|
|
||||||
# hex_string = "$fingerprint"
|
|
||||||
|
|
||||||
# # Convert hex to binary
|
|
||||||
# binary_data = binascii.unhexlify(hex_string)
|
|
||||||
|
|
||||||
# # Encode binary data to base64
|
|
||||||
# base64_encoded = base64.b64encode(binary_data).decode('utf-8')
|
|
||||||
|
|
||||||
# # Print the result prefixed with 'sha256/'
|
|
||||||
# print('sha256/' + base64_encoded)
|
|
||||||
# EOF
|
|
||||||
# )
|
|
||||||
|
|
||||||
echo "SHA-256 fingerprint generated: $sha256"
|
echo "SHA-256 fingerprint generated: $sha256"
|
||||||
|
|
||||||
if [ -f "$CONFIG_FILE" ]; then
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
@ -50,9 +94,7 @@ update_sni() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$CONFIG_ENV" ]; then
|
if [ -f "$CONFIG_ENV" ]; then
|
||||||
|
|
||||||
if grep -q "^SNI=" "$CONFIG_ENV"; then
|
if grep -q "^SNI=" "$CONFIG_ENV"; then
|
||||||
|
|
||||||
sed -i "s/^SNI=.*$/SNI=$sni/" "$CONFIG_ENV"
|
sed -i "s/^SNI=.*$/SNI=$sni/" "$CONFIG_ENV"
|
||||||
echo "SNI updated successfully in $CONFIG_ENV"
|
echo "SNI updated successfully in $CONFIG_ENV"
|
||||||
else
|
else
|
||||||
@ -66,6 +108,15 @@ update_sni() {
|
|||||||
|
|
||||||
python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1
|
python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1
|
||||||
echo "Hysteria2 restarted successfully with new SNI: $sni."
|
echo "Hysteria2 restarted successfully with new SNI: $sni."
|
||||||
|
|
||||||
|
if [ "$use_certbot" = true ]; then
|
||||||
|
echo "✅ Valid Let's Encrypt certificate installed for $sni"
|
||||||
|
echo " TLS insecure mode is now DISABLED"
|
||||||
|
else
|
||||||
|
echo "⚠️ Self-signed certificate installed for $sni"
|
||||||
|
echo " TLS insecure mode is now ENABLED"
|
||||||
|
echo " (This certificate won't be trusted by browsers)"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
update_sni "$1"
|
update_sni "$sni"
|
||||||
@ -66,11 +66,10 @@ def is_service_active(service_name: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def generate_uri(username: str, auth_password: str, ip: str, port: str,
|
def generate_uri(username: str, auth_password: str, ip: str, port: str,
|
||||||
obfs_password: str, sha256: str, sni: str, ip_version: int) -> str:
|
obfs_password: str, sha256: str, sni: str, ip_version: int, insecure: bool) -> str:
|
||||||
"""Generate Hysteria2 URI for the given parameters."""
|
"""Generate Hysteria2 URI for the given parameters."""
|
||||||
uri_base = f"hy2://{username}%3A{auth_password}@{ip}:{port}"
|
uri_base = f"hy2://{username}%3A{auth_password}@{ip}:{port}"
|
||||||
|
|
||||||
# Handle IPv6 address formatting
|
|
||||||
if ip_version == 6 and re.match(r'^[0-9a-fA-F:]+$', ip):
|
if ip_version == 6 and re.match(r'^[0-9a-fA-F:]+$', ip):
|
||||||
uri_base = f"hy2://{username}%3A{auth_password}@[{ip}]:{port}"
|
uri_base = f"hy2://{username}%3A{auth_password}@[{ip}]:{port}"
|
||||||
|
|
||||||
@ -82,7 +81,8 @@ def generate_uri(username: str, auth_password: str, ip: str, port: str,
|
|||||||
if sha256:
|
if sha256:
|
||||||
params.append(f"pinSHA256={sha256}")
|
params.append(f"pinSHA256={sha256}")
|
||||||
|
|
||||||
params.append(f"insecure=1&sni={sni}")
|
insecure_value = "1" if insecure else "0"
|
||||||
|
params.append(f"insecure={insecure_value}&sni={sni}")
|
||||||
|
|
||||||
params_str = "&".join(params)
|
params_str = "&".join(params)
|
||||||
return f"{uri_base}?{params_str}#{username}-IPv{ip_version}"
|
return f"{uri_base}?{params_str}#{username}-IPv{ip_version}"
|
||||||
@ -138,6 +138,8 @@ def show_uri(args: argparse.Namespace) -> None:
|
|||||||
sha256 = config.get("tls", {}).get("pinSHA256", "")
|
sha256 = config.get("tls", {}).get("pinSHA256", "")
|
||||||
obfs_password = config.get("obfs", {}).get("salamander", {}).get("password", "")
|
obfs_password = config.get("obfs", {}).get("salamander", {}).get("password", "")
|
||||||
|
|
||||||
|
insecure = config.get("tls", {}).get("insecure", True)
|
||||||
|
|
||||||
ip4, ip6, sni = load_hysteria2_ips()
|
ip4, ip6, sni = load_hysteria2_ips()
|
||||||
available_ip4 = ip4 and ip4 != "None"
|
available_ip4 = ip4 and ip4 != "None"
|
||||||
available_ip6 = ip6 and ip6 != "None"
|
available_ip6 = ip6 and ip6 != "None"
|
||||||
@ -148,21 +150,21 @@ def show_uri(args: argparse.Namespace) -> None:
|
|||||||
if args.all:
|
if args.all:
|
||||||
if available_ip4:
|
if available_ip4:
|
||||||
uri_ipv4 = generate_uri(args.username, auth_password, ip4, port,
|
uri_ipv4 = generate_uri(args.username, auth_password, ip4, port,
|
||||||
obfs_password, sha256, sni, 4)
|
obfs_password, sha256, sni, 4, insecure)
|
||||||
print(f"\nIPv4:\n{uri_ipv4}\n")
|
print(f"\nIPv4:\n{uri_ipv4}\n")
|
||||||
|
|
||||||
if available_ip6:
|
if available_ip6:
|
||||||
uri_ipv6 = generate_uri(args.username, auth_password, ip6, port,
|
uri_ipv6 = generate_uri(args.username, auth_password, ip6, port,
|
||||||
obfs_password, sha256, sni, 6)
|
obfs_password, sha256, sni, 6, insecure)
|
||||||
print(f"\nIPv6:\n{uri_ipv6}\n")
|
print(f"\nIPv6:\n{uri_ipv6}\n")
|
||||||
else:
|
else:
|
||||||
if args.ip_version == 4 and available_ip4:
|
if args.ip_version == 4 and available_ip4:
|
||||||
uri_ipv4 = generate_uri(args.username, auth_password, ip4, port,
|
uri_ipv4 = generate_uri(args.username, auth_password, ip4, port,
|
||||||
obfs_password, sha256, sni, 4)
|
obfs_password, sha256, sni, 4, insecure)
|
||||||
print(f"\nIPv4:\n{uri_ipv4}\n")
|
print(f"\nIPv4:\n{uri_ipv4}\n")
|
||||||
elif args.ip_version == 6 and available_ip6:
|
elif args.ip_version == 6 and available_ip6:
|
||||||
uri_ipv6 = generate_uri(args.username, auth_password, ip6, port,
|
uri_ipv6 = generate_uri(args.username, auth_password, ip6, port,
|
||||||
obfs_password, sha256, sni, 6)
|
obfs_password, sha256, sni, 6, insecure)
|
||||||
print(f"\nIPv6:\n{uri_ipv6}\n")
|
print(f"\nIPv6:\n{uri_ipv6}\n")
|
||||||
else:
|
else:
|
||||||
print("Invalid IP version or no available IP for the requested version.")
|
print("Invalid IP version or no available IP for the requested version.")
|
||||||
|
|||||||
Reference in New Issue
Block a user