From 441d212ef2a0893ed912c53cb276b44871997f17 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Mon, 5 Jan 2015 10:47:20 -0800 Subject: [PATCH] add ipv6 detection for external port binding --- plugins/domains/commands | 17 ++++++++++++++++- plugins/nginx-vhosts/bind-external-ip | 21 ++++++++++++++++++--- tests/unit/ports.bats | 13 ++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/plugins/domains/commands b/plugins/domains/commands index 05f6758f6..9ae7bec38 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -1,6 +1,21 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" + +RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 +RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 +RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: +RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) +RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + case "$1" in domains) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -23,7 +38,7 @@ case "$1" in else VHOST=$(< "$DOKKU_ROOT/HOSTNAME") fi - if [[ "$VHOST" =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]];then + if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]];then echo "ip found as hostname. disabling vhost support" [[ ! $(grep -q NO_VHOST "$DOKKU_ROOT/$APP/ENV") ]] && echo "export NO_VHOST='1'" >> "$DOKKU_ROOT/$APP/ENV" else diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index 55159289e..636bc894c 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -2,8 +2,23 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x APP="$1" - set +e; NO_VHOST=$(dokku config:get $APP NO_VHOST); set -e + +RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" + +RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 +RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 +RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: +RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) +RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) +RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + if [[ -f "$DOKKU_ROOT/VHOST" ]];then GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") else @@ -12,8 +27,8 @@ fi if [[ -n "$NO_VHOST" ]]; then echo true # bind to external ip. VHOST is disabled for this app -elif [[ "$GLOBAL_VHOST" =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]];then - echo true # bind to external ip. GLOBAL_VHOST is somehow an IP +elif [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then + echo true # bind to external ip. GLOBAL_VHOST is somehow an IPv4 or IPv6 address elif [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then echo false # bind to docker ip. this app has a vhost defined else diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats index 76166ea53..ebafd23a5 100644 --- a/tests/unit/ports.bats +++ b/tests/unit/ports.bats @@ -45,7 +45,7 @@ teardown() { assert_success } -@test "port exposure (without global VHOST and ip as HOSTNAME)" { +@test "port exposure (without global VHOST and IPv4 address as HOSTNAME)" { rm "$DOKKU_ROOT/VHOST" echo "127.0.0.1" > "$DOKKU_ROOT/HOSTNAME" deploy_app @@ -55,3 +55,14 @@ teardown() { echo "status: "$status assert_success } + +@test "port exposure (without global VHOST and IPv6 address as HOSTNAME)" { + rm "$DOKKU_ROOT/VHOST" + echo "fda5:c7db:a520:bb6d::aabb:ccdd:eeff" > "$DOKKU_ROOT/HOSTNAME" + deploy_app + CONTAINER_ID=$(docker ps --no-trunc| grep dokku/$TEST_APP | grep "start web" | awk '{ print $1 }') + run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" + echo "output: "$output + echo "status: "$status + assert_success +}