From cfffb38508fc85a1d2d3cd452a2086c2d9278373 Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Sun, 31 Aug 2014 08:09:13 -0400 Subject: [PATCH] link-local IPv6 addresses need a '%interface' specification to be useful --- setup/functions.sh | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/setup/functions.sh b/setup/functions.sh index 78e67eda..23c2492b 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -85,6 +85,9 @@ function get_default_privateip { # Return the IP address of the network interface connected # to the Internet. # + # Pass '4' or '6' as an argument to this function to specify + # what type of address to get (IPv4, IPv6). + # # We used to use `hostname -I` and then filter for either # IPv4 or IPv6 addresses. However if there are multiple # network interfaces on the machine, not all may be for @@ -99,11 +102,16 @@ function get_default_privateip { # assigned to an interface. `ip route get` reports the # preferred. That's good enough for us. See issue #121. # + # With IPv6, the best route may be via an interface that + # only has a link-local address (fe80::*). These addresses + # are only unique to an interface and so need an explicit + # interface specification in order to use them with bind(). + # In these cases, we append "%interface" to the address. + # See the Notes section in the man page for getaddrinfo and + # https://discourse.mailinabox.email/t/update-broke-mailinabox/34/9. + # # Also see ae67409603c49b7fa73c227449264ddd10aae6a9 and # issue #3 for why/how we originally added IPv6. - # - # Pass '4' or '6' as an argument to this function to specify - # what type of address to get (IPv4, IPv6). target=8.8.8.8 @@ -112,9 +120,21 @@ function get_default_privateip { # as it's an address on the public Internet. if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi - ip -$1 -o route get $target \ - | grep -v unreachable \ - | sed "s/.* src \([^ ]*\).*/\1/" + # Get the route information. + route=$(ip -$1 -o route get $target | grep -v unreachable) + + # Parse the address out of the route information. + address=$(echo $route | sed "s/.* src \([^ ]*\).*/\1/") + + if [[ "$1" == "6" && $address == fe80:* ]]; then + # For IPv6 link-local addresses, parse the interface out + # of the route information and append it with a '%'. + interface=$(echo $route | sed "s/.* dev \([^ ]*\).*/\1/") + address=$address%$interface + fi + + echo $address + } function ufw_allow {