diff --git a/docker/coturn/alpine/Dockerfile b/docker/coturn/alpine/Dockerfile index ac06a36..05f0e4d 100644 --- a/docker/coturn/alpine/Dockerfile +++ b/docker/coturn/alpine/Dockerfile @@ -109,6 +109,9 @@ RUN apk update \ libpq mariadb-connector-c sqlite-libs \ hiredis \ mongo-c-driver \ + # Install `dig` tool for `detect-external-ip.sh`. + && apk add --no-cache \ + bind-tools \ # Cleanup unnecessary stuff. && rm -rf /var/cache/apk/* diff --git a/docker/coturn/alpine/rootfs/usr/local/bin/detect-external-ip.sh b/docker/coturn/alpine/rootfs/usr/local/bin/detect-external-ip.sh index b4e4c57..49bdc8d 100644 --- a/docker/coturn/alpine/rootfs/usr/local/bin/detect-external-ip.sh +++ b/docker/coturn/alpine/rootfs/usr/local/bin/detect-external-ip.sh @@ -1,7 +1,115 @@ -#!/bin/sh +#!/usr/bin/env sh +# shellcheck shell=dash -if [ -z "$REAL_EXTERNAL_IP" ]; then - export REAL_EXTERNAL_IP="$(curl -4 https://icanhazip.com 2>/dev/null)" +#/ Use DNS to find out about the external IP of the running system. +#/ +#/ This script is useful when running from a machine that sits behind a NAT. +#/ Due to how NAT works, machines behind it belong to an internal or private +#/ subnet, with a different address space than the external or public side. +#/ +#/ Typically it is possible to make an HTTP request to a number of providers +#/ that offer the external IP in their response body (eg: ifconfig.me). However, +#/ why do a slow and heavy HTTP request, when DNS exists and is much faster? +#/ Well established providers such as OpenDNS or Google offer special hostnames +#/ that, when resolved, will actually return the IP address of the caller. +#/ +#/ https://unix.stackexchange.com/questions/22615/how-can-i-get-my-external-ip-address-in-a-shell-script/81699#81699 +#/ +#/ +#/ Arguments +#/ --------- +#/ +#/ --ipv4 +#/ +#/ Find the external IPv4 address. +#/ Optional. Default: Enabled. +#/ +#/ --ipv6 +#/ +#/ Find the external IPv6 address. +#/ Optional. Default: Disabled. + + + +# Shell setup +# =========== + +# Shell options for strict error checking. +for OPTION in errexit errtrace pipefail nounset; do + set -o | grep -wq "$OPTION" && set -o "$OPTION" +done + +# Trace all commands (to stderr). +#set -o xtrace + + + +# Shortcut: REAL_EXTERNAL_IP +# ========================== + +if [ -n "${REAL_EXTERNAL_IP:-}" ]; then + echo "$REAL_EXTERNAL_IP" + exit 0 fi -exec echo "$REAL_EXTERNAL_IP" + + +# Parse call arguments +# ==================== + +CFG_IPV4="true" + +while [ $# -gt 0 ]; do + case "${1-}" in + --ipv4) CFG_IPV4="true" ;; + --ipv6) CFG_IPV4="false" ;; + *) + echo "Invalid argument: '${1-}'" >&2 + exit 1 + ;; + esac + shift +done + + + +# Discover the external IP address +# ================================ + +if [ "$CFG_IPV4" = "true" ]; then + COMMANDS='dig @resolver1.opendns.com myip.opendns.com A -4 +short + dig @ns1.google.com o-o.myaddr.l.google.com TXT -4 +short | tr -d \" + dig @1.1.1.1 whoami.cloudflare TXT CH -4 +short | tr -d \" + dig @ns1-1.akamaitech.net whoami.akamai.net A -4 +short' + + is_valid_ip() { + # Check if the input looks like an IPv4 address. + # Doesn't check if the actual values are valid; assumes they are. + echo "$1" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$' + } +else + COMMANDS='dig @resolver1.opendns.com myip.opendns.com AAAA -6 +short + dig @ns1.google.com o-o.myaddr.l.google.com TXT -6 +short | tr -d \" + dig @2606:4700:4700::1111 whoami.cloudflare TXT CH -6 +short | tr -d \"' + + is_valid_ip() { + # Check if the input looks like an IPv6 address. + # It's almost impossible to check the IPv6 representation because it + # varies wildly, so just check that there are at least 2 colons. + [ "$(echo "$1" | awk -F':' '{print NF-1}')" -ge 2 ] + } +fi + +echo "$COMMANDS" | while read -r COMMAND; do + if IP="$(eval "$COMMAND")" && is_valid_ip "$IP"; then + echo "$IP" + exit 100 # Exits the pipe subshell. + fi +done + +if [ $? -eq 100 ]; then + exit 0 +else + echo "[$0] All providers failed" >&2 + exit 1 +fi diff --git a/docker/coturn/debian/Dockerfile b/docker/coturn/debian/Dockerfile index 7b64b39..0b4eeb0 100644 --- a/docker/coturn/debian/Dockerfile +++ b/docker/coturn/debian/Dockerfile @@ -164,6 +164,9 @@ RUN apt-get update \ libssl1.1 \ libpq5 libmariadb3 libsqlite3-0 \ libhiredis0.14 \ + # Install `dig` tool for `detect-external-ip.sh`. + && apt-get install -y --no-install-recommends --no-install-suggests \ + dnsutils \ # Cleanup unnecessary stuff. && rm -rf /var/lib/apt/lists/* diff --git a/docker/coturn/debian/rootfs/usr/local/bin/detect-external-ip.sh b/docker/coturn/debian/rootfs/usr/local/bin/detect-external-ip.sh index b4e4c57..49bdc8d 100644 --- a/docker/coturn/debian/rootfs/usr/local/bin/detect-external-ip.sh +++ b/docker/coturn/debian/rootfs/usr/local/bin/detect-external-ip.sh @@ -1,7 +1,115 @@ -#!/bin/sh +#!/usr/bin/env sh +# shellcheck shell=dash -if [ -z "$REAL_EXTERNAL_IP" ]; then - export REAL_EXTERNAL_IP="$(curl -4 https://icanhazip.com 2>/dev/null)" +#/ Use DNS to find out about the external IP of the running system. +#/ +#/ This script is useful when running from a machine that sits behind a NAT. +#/ Due to how NAT works, machines behind it belong to an internal or private +#/ subnet, with a different address space than the external or public side. +#/ +#/ Typically it is possible to make an HTTP request to a number of providers +#/ that offer the external IP in their response body (eg: ifconfig.me). However, +#/ why do a slow and heavy HTTP request, when DNS exists and is much faster? +#/ Well established providers such as OpenDNS or Google offer special hostnames +#/ that, when resolved, will actually return the IP address of the caller. +#/ +#/ https://unix.stackexchange.com/questions/22615/how-can-i-get-my-external-ip-address-in-a-shell-script/81699#81699 +#/ +#/ +#/ Arguments +#/ --------- +#/ +#/ --ipv4 +#/ +#/ Find the external IPv4 address. +#/ Optional. Default: Enabled. +#/ +#/ --ipv6 +#/ +#/ Find the external IPv6 address. +#/ Optional. Default: Disabled. + + + +# Shell setup +# =========== + +# Shell options for strict error checking. +for OPTION in errexit errtrace pipefail nounset; do + set -o | grep -wq "$OPTION" && set -o "$OPTION" +done + +# Trace all commands (to stderr). +#set -o xtrace + + + +# Shortcut: REAL_EXTERNAL_IP +# ========================== + +if [ -n "${REAL_EXTERNAL_IP:-}" ]; then + echo "$REAL_EXTERNAL_IP" + exit 0 fi -exec echo "$REAL_EXTERNAL_IP" + + +# Parse call arguments +# ==================== + +CFG_IPV4="true" + +while [ $# -gt 0 ]; do + case "${1-}" in + --ipv4) CFG_IPV4="true" ;; + --ipv6) CFG_IPV4="false" ;; + *) + echo "Invalid argument: '${1-}'" >&2 + exit 1 + ;; + esac + shift +done + + + +# Discover the external IP address +# ================================ + +if [ "$CFG_IPV4" = "true" ]; then + COMMANDS='dig @resolver1.opendns.com myip.opendns.com A -4 +short + dig @ns1.google.com o-o.myaddr.l.google.com TXT -4 +short | tr -d \" + dig @1.1.1.1 whoami.cloudflare TXT CH -4 +short | tr -d \" + dig @ns1-1.akamaitech.net whoami.akamai.net A -4 +short' + + is_valid_ip() { + # Check if the input looks like an IPv4 address. + # Doesn't check if the actual values are valid; assumes they are. + echo "$1" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$' + } +else + COMMANDS='dig @resolver1.opendns.com myip.opendns.com AAAA -6 +short + dig @ns1.google.com o-o.myaddr.l.google.com TXT -6 +short | tr -d \" + dig @2606:4700:4700::1111 whoami.cloudflare TXT CH -6 +short | tr -d \"' + + is_valid_ip() { + # Check if the input looks like an IPv6 address. + # It's almost impossible to check the IPv6 representation because it + # varies wildly, so just check that there are at least 2 colons. + [ "$(echo "$1" | awk -F':' '{print NF-1}')" -ge 2 ] + } +fi + +echo "$COMMANDS" | while read -r COMMAND; do + if IP="$(eval "$COMMAND")" && is_valid_ip "$IP"; then + echo "$IP" + exit 100 # Exits the pipe subshell. + fi +done + +if [ $? -eq 100 ]; then + exit 0 +else + echo "[$0] All providers failed" >&2 + exit 1 +fi