Commit 168c0693 authored by Joshua Tauberer's avatar Joshua Tauberer

have nsd bind to the network interaface that is connected to the Internet,...

have nsd bind to the network interaface that is connected to the Internet, rather than all non-loopback network interfaces

hopefully fixes #121; thanks for the help @sfPlayer1
parent c74bef12
......@@ -104,7 +104,7 @@ def do_dns_update(env):
zonefiles[i][1] += ".signed"
# Write the main nsd.conf file.
if write_nsd_conf(zonefiles):
if write_nsd_conf(zonefiles, env):
# Make sure updated_domains contains *something* if we wrote an updated
# nsd.conf so that we know to restart nsd.
if len(updated_domains) == 0:
......@@ -383,7 +383,7 @@ $TTL 86400 ; default time to live
########################################################################
def write_nsd_conf(zonefiles):
def write_nsd_conf(zonefiles, env):
# Basic header.
nsdconf = """
server:
......@@ -397,15 +397,13 @@ server:
"""
# Since we have bind9 listening on localhost for locally-generated
# DNS queries that require a recursive nameserver, we must have
# nsd listen only on public network interfaces. Those interfaces
# may have addresses different from the public IP address that the
# Internet sees this machine on. Get those interface addresses
# from `hostname -i` (which omits all localhost addresses).
for ipaddr in shell("check_output", ["/bin/hostname", "-I"]).strip().split(" "):
# DNS queries that require a recursive nameserver, and the system
# might have other network interfaces for e.g. tunnelling, we have
# to be specific about the network interfaces that nsd binds to.
for ipaddr in (env.get("PRIVATE_IP", "") + " " + env.get("PRIVATE_IPV6", "")).split(" "):
if ipaddr == "": continue
nsdconf += " ip-address: %s\n" % ipaddr
# Append the zones.
for domain, zonefile in zonefiles:
nsdconf += """
......
......@@ -77,62 +77,58 @@ function get_default_publicip {
# API, but if that fails (maybe we don't have Internet access
# right now) then use the IP address that this machine knows
# itself as.
get_publicip_from_web_service || get_publicip_fallback
get_publicip_from_web_service 4 || get_default_privateip 4
}
function get_default_publicipv6 {
get_publicipv6_from_web_service || get_publicipv6_fallback
get_publicip_from_web_service 6 || get_default_privateip 6
}
function get_publicip_from_web_service {
# This seems to be the most reliable way to determine the
# machine's public IP address: asking a very nice web API
# for how they see us. Thanks go out to icanhazip.com.
curl -4 --fail --silent icanhazip.com 2>/dev/null
}
function get_publicipv6_from_web_service {
curl -6 --fail --silent icanhazip.com 2>/dev/null
}
function get_publicip_fallback {
# Return the IP address that this machine knows itself as.
# It certainly may not be the IP address that this machine
# operates as on the public Internet. The machine might
# have multiple addresses if it has multiple network adapters.
set -- $(hostname --ip-address 2>/dev/null) \
$(hostname --all-ip-addresses 2>/dev/null)
while (( $# )) && { ! is_ipv4 "$1" || is_loopback_ip "$1"; }; do
shift
done
printf '%s\n' "$1" # return this value
}
function get_publicipv6_fallback {
set -- $(hostname --ip-address 2>/dev/null) \
$(hostname --all-ip-addresses 2>/dev/null)
while (( $# )) && { ! is_ipv6 "$1" || is_loopback_ipv6 "$1"; }; do
shift
done
printf '%s\n' "$1" # return this value
# See: https://major.io/icanhazip-com-faq/
#
# Pass '4' or '6' as an argument to this function to specify
# what type of address to get (IPv4, IPv6).
curl -$1 --fail --silent icanhazip.com 2>/dev/null
}
function is_ipv4 {
# helper for get_publicip_fallback
[[ "$1" == *.*.*.* ]]
}
function get_default_privateip {
# Return the IP address of the network interface connected
# to the Internet.
#
# 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
# reaching the Internet.
#
# Instead use `ip route get` which asks the kernel to use
# the system's routes to select which interface would be
# used to reach a public address. We'll use 8.8.8.8 as
# the destination. It happens to be Google Public DNS, but
# no connection is made. We're just seeing how the box
# would connect to it. There many be multiple IP addresses
# assigned to an interface. `ip route get` reports the
# preferred. That's good enough for us. See issue #121.
#
# 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).
function is_ipv6 {
[[ "$1" == *:*:* ]]
}
target=8.8.8.8
function is_loopback_ip {
# helper for get_publicip_fallback
[[ "$1" == 127.* ]]
}
# For the IPv6 route, use the corresponding IPv6 address
# of Google Public DNS. Again, it doesn't matter so long
# as it's an address on the public Internet.
if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi
function is_loopback_ipv6 {
[[ "$1" == ::1 ]]
ip -$1 -o route get $target \
| grep -v unreachable \
| sed "s/.* src \([^ ]*\).*/\1/"
}
function ufw_allow {
......
......@@ -136,6 +136,26 @@ if [ -z "$PUBLIC_IPV6" ]; then
read -e -i "$DEFAULT_PUBLIC_IPV6" -p "Public IPv6: " PUBLIC_IPV6
fi
# Get the IP addresses of the local network interface(s) that are connected
# to the Internet. We need these when we want to have services bind only to
# the public network interfaces (not loopback, not tunnel interfaces).
if [ -z "$PRIVATE_IP" ]; then
PRIVATE_IP=$(get_default_privateip 4)
fi
if [ -z "$PRIVATE_IPV6" ]; then
PRIVATE_IPV6=$(get_default_privateip 6)
fi
if [[ -z "$PRIVATE_IP" && -z "$PRIVATE_IPV6" ]]; then
echo
echo "I could not determine the IP or IPv6 address of the network inteface"
echo "for connecting to the Internet. Setup must stop."
echo
hostname -I
route
echo
exit
fi
# We need a country code to generate a certificate signing request. However
# if a CSR already exists then we won't be generating a new one and there's
# no reason to ask for the country code now. $STORAGE_ROOT has not yet been
......@@ -199,6 +219,8 @@ STORAGE_ROOT=$STORAGE_ROOT
PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME
PUBLIC_IP=$PUBLIC_IP
PUBLIC_IPV6=$PUBLIC_IPV6
PRIVATE_IP=$PRIVATE_IP
PRIVATE_IPV6=$PRIVATE_IPV6
CSR_COUNTRY=$CSR_COUNTRY
MIGRATIONID=$MIGRATIONID
EOF
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment