Merge pull request #753 from j1elo/master

Use DNS requests to discover external IP address
This commit is contained in:
Kai Ren 2021-06-03 10:09:29 +03:00 committed by GitHub
commit 55b506c4a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 213 additions and 14 deletions

View File

@ -2,6 +2,7 @@
!docker/coturn/alpine/
!docker/coturn/debian/
!docker/coturn/rootfs/
!cmake/
!CMakeLists.txt

View File

@ -11,10 +11,15 @@ Coturn TURN server Docker image changelog
- [Prometheus] support with [prometheus-client-c] 0.1.3: <https://github.com/digitalocean/prometheus-client-c/releases/tag/v0.1.3> ([#754])
### Improved
- Use DNS requests to discover external IP address in `detect-external-ip` script ([#753]).
### Fixed
- Incorrect linking with [mongo-c-driver] on [Debian Linux] image.
[#753]: /../../pull/753
[#754]: /../../pull/754

View File

@ -176,6 +176,7 @@ docker.push:
# [( [build=no]
# | build=yes [DOCKERFILE=(debian|alpine)]
# [ref=<git-ref>] )]
# [with=ipv6]
test-docker-platforms = $(strip $(if $(call eq,$(platforms),),$(MAIN_PLATFORM),\
$(if $(call eq,$(platforms),@all),$(PLATFORMS),\
@ -195,6 +196,7 @@ define test.docker.do
@make docker.image DOCKERFILE=$(DOCKERFILE) \
no-cache=no tag=$(tag) platform=$(platform) ref=$(ref) ,)
IMAGE=coturn/$(NAME):$(tag) PLATFORM=$(platform) \
$(if $(call eq,$(with),ipv6),TEST_IPV6=1,) \
node_modules/.bin/bats \
--timing $(if $(call eq,$(CI),),--pretty,--formatter tap) \
tests/main.bats

View File

@ -110,6 +110,14 @@ docker run -d --network=host coturn/coturn \
--relay-ip='$(detect-external-ip)'
```
By default, [IPv4] address is discovered. In case you need an [IPv6] one, specify the `--ipv6` flag:
```bash
docker run -d --network=host coturn/coturn \
-n --log-file=stdout \
--external-ip='$(detect-external-ip --ipv6)' \
--relay-ip='$(detect-external-ip --ipv6)'
```
### Persistence
@ -185,6 +193,8 @@ If you have any problems with or questions about this image, please contact us t
[DockerHub]: https://hub.docker.com
[IPv4]: https://en.wikipedia.org/wiki/IPv4
[IPv6]: https://en.wikipedia.org/wiki/IPv6
[RFC 5766 Section 6.2]: https://tools.ietf.org/html/rfc5766.html#section-6.2
[1]: http://alpinelinux.org

View File

@ -150,6 +150,7 @@ RUN mkdir -p /out/ \
&& rm -f /out/etc/coturn/turnserver.conf.default
# Install helper tools of Docker image.
COPY docker/coturn/rootfs/ /out/
COPY docker/coturn/alpine/rootfs/ /out/
RUN chmod +x /out/usr/local/bin/docker-entrypoint.sh \
/out/usr/local/bin/detect-external-ip.sh
@ -185,6 +186,9 @@ RUN apk update \
hiredis \
mongo-c-driver \
libmicrohttpd \
# Install `dig` tool for `detect-external-ip.sh`.
&& apk add --no-cache \
bind-tools \
# Cleanup unnecessary stuff.
&& rm -rf /var/cache/apk/*

View File

@ -1,7 +0,0 @@
#!/bin/sh
if [ -z "$REAL_EXTERNAL_IP" ]; then
export REAL_EXTERNAL_IP="$(curl -4 https://icanhazip.com 2>/dev/null)"
fi
exec echo "$REAL_EXTERNAL_IP"

View File

@ -207,6 +207,7 @@ RUN mkdir -p /out/ \
&& rm -f /out/etc/coturn/turnserver.conf.default
# Install helper tools of Docker image.
COPY docker/coturn/rootfs/ /out/
COPY docker/coturn/debian/rootfs/ /out/
RUN chmod +x /out/usr/local/bin/docker-entrypoint.sh \
/out/usr/local/bin/detect-external-ip.sh
@ -246,6 +247,9 @@ RUN apt-get update \
libpq5 libmariadb3 libsqlite3-0 \
libhiredis0.14 \
libmicrohttpd12 \
# 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/*

View File

@ -1,7 +0,0 @@
#!/bin/sh
if [ -z "$REAL_EXTERNAL_IP" ]; then
export REAL_EXTERNAL_IP="$(curl -4 https://icanhazip.com 2>/dev/null)"
fi
exec echo "$REAL_EXTERNAL_IP"

View File

@ -0,0 +1,112 @@
#!/usr/bin/env sh
# shellcheck shell=dash
#/ 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
# 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
IFS="$(printf '\nx')" && IFS="${IFS%x}"
for COMMAND in $COMMANDS; do
if IP="$(eval "$COMMAND")" && is_valid_ip "$IP"; then
printf '%s' "$IP"
exit 0
fi
done
echo "[$0] All providers failed" >&2
exit 1

View File

@ -125,3 +125,78 @@
[ "$status" -eq 0 ]
[ ! "$output" = '' ]
}
@test "detect-external-ip is present" {
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'which detect-external-ip'
[ "$status" -eq 0 ]
}
@test "detect-external-ip runs ok" {
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'detect-external-ip'
[ "$status" -eq 0 ]
}
@test "detect-external-ip returns valid IPv4" {
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'detect-external-ip --ipv4'
[ "$status" -eq 0 ]
run validate_ipv4 "$output"
[ "$status" -eq 0 ]
}
@test "detect-external-ip returns valid IPv6" {
[ -z "$TEST_IPV6" ] && skip
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'detect-external-ip --ipv6'
[ "$status" -eq 0 ]
run validate_ipv6 "$output"
[ "$status" -eq 0 ]
}
@test "detect-external-ip returns IPv4 by default" {
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'detect-external-ip --ipv4'
[ "$status" -eq 0 ]
run validate_ipv4 "$output"
[ "$status" -eq 0 ]
}
#
# Helpers
#
# Tests the IP address to be a valid IPv4 address.
function validate_ipv4() {
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return $stat
}
# Tests the IP address to be a valid IPv6 address.
function validate_ipv6() {
local ip=$1
local stat=1
if [[ $ip =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$ ]]; then
stat=0
fi
return $stat
}