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): ...@@ -104,7 +104,7 @@ def do_dns_update(env):
zonefiles[i][1] += ".signed" zonefiles[i][1] += ".signed"
# Write the main nsd.conf file. # 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 # Make sure updated_domains contains *something* if we wrote an updated
# nsd.conf so that we know to restart nsd. # nsd.conf so that we know to restart nsd.
if len(updated_domains) == 0: if len(updated_domains) == 0:
...@@ -383,7 +383,7 @@ $TTL 86400 ; default time to live ...@@ -383,7 +383,7 @@ $TTL 86400 ; default time to live
######################################################################## ########################################################################
def write_nsd_conf(zonefiles): def write_nsd_conf(zonefiles, env):
# Basic header. # Basic header.
nsdconf = """ nsdconf = """
server: server:
...@@ -397,15 +397,13 @@ server: ...@@ -397,15 +397,13 @@ server:
""" """
# Since we have bind9 listening on localhost for locally-generated # Since we have bind9 listening on localhost for locally-generated
# DNS queries that require a recursive nameserver, we must have # DNS queries that require a recursive nameserver, and the system
# nsd listen only on public network interfaces. Those interfaces # might have other network interfaces for e.g. tunnelling, we have
# may have addresses different from the public IP address that the # to be specific about the network interfaces that nsd binds to.
# Internet sees this machine on. Get those interface addresses for ipaddr in (env.get("PRIVATE_IP", "") + " " + env.get("PRIVATE_IPV6", "")).split(" "):
# from `hostname -i` (which omits all localhost addresses). if ipaddr == "": continue
for ipaddr in shell("check_output", ["/bin/hostname", "-I"]).strip().split(" "):
nsdconf += " ip-address: %s\n" % ipaddr nsdconf += " ip-address: %s\n" % ipaddr
# Append the zones. # Append the zones.
for domain, zonefile in zonefiles: for domain, zonefile in zonefiles:
nsdconf += """ nsdconf += """
......
...@@ -77,62 +77,58 @@ function get_default_publicip { ...@@ -77,62 +77,58 @@ function get_default_publicip {
# API, but if that fails (maybe we don't have Internet access # API, but if that fails (maybe we don't have Internet access
# right now) then use the IP address that this machine knows # right now) then use the IP address that this machine knows
# itself as. # itself as.
get_publicip_from_web_service || get_publicip_fallback get_publicip_from_web_service 4 || get_default_privateip 4
} }
function get_default_publicipv6 { 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 { function get_publicip_from_web_service {
# This seems to be the most reliable way to determine the # This seems to be the most reliable way to determine the
# machine's public IP address: asking a very nice web API # machine's public IP address: asking a very nice web API
# for how they see us. Thanks go out to icanhazip.com. # for how they see us. Thanks go out to icanhazip.com.
curl -4 --fail --silent icanhazip.com 2>/dev/null # See: https://major.io/icanhazip-com-faq/
} #
# Pass '4' or '6' as an argument to this function to specify
function get_publicipv6_from_web_service { # what type of address to get (IPv4, IPv6).
curl -6 --fail --silent icanhazip.com 2>/dev/null curl -$1 --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
} }
function is_ipv4 { function get_default_privateip {
# helper for get_publicip_fallback # Return the IP address of the network interface connected
[[ "$1" == *.*.*.* ]] # 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 { target=8.8.8.8
[[ "$1" == *:*:* ]]
}
function is_loopback_ip { # For the IPv6 route, use the corresponding IPv6 address
# helper for get_publicip_fallback # of Google Public DNS. Again, it doesn't matter so long
[[ "$1" == 127.* ]] # as it's an address on the public Internet.
} if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi
function is_loopback_ipv6 { ip -$1 -o route get $target \
[[ "$1" == ::1 ]] | grep -v unreachable \
| sed "s/.* src \([^ ]*\).*/\1/"
} }
function ufw_allow { function ufw_allow {
......
...@@ -136,6 +136,26 @@ if [ -z "$PUBLIC_IPV6" ]; then ...@@ -136,6 +136,26 @@ if [ -z "$PUBLIC_IPV6" ]; then
read -e -i "$DEFAULT_PUBLIC_IPV6" -p "Public IPv6: " PUBLIC_IPV6 read -e -i "$DEFAULT_PUBLIC_IPV6" -p "Public IPv6: " PUBLIC_IPV6
fi 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 # 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 # 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 # no reason to ask for the country code now. $STORAGE_ROOT has not yet been
...@@ -199,6 +219,8 @@ STORAGE_ROOT=$STORAGE_ROOT ...@@ -199,6 +219,8 @@ STORAGE_ROOT=$STORAGE_ROOT
PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME
PUBLIC_IP=$PUBLIC_IP PUBLIC_IP=$PUBLIC_IP
PUBLIC_IPV6=$PUBLIC_IPV6 PUBLIC_IPV6=$PUBLIC_IPV6
PRIVATE_IP=$PRIVATE_IP
PRIVATE_IPV6=$PRIVATE_IPV6
CSR_COUNTRY=$CSR_COUNTRY CSR_COUNTRY=$CSR_COUNTRY
MIGRATIONID=$MIGRATIONID MIGRATIONID=$MIGRATIONID
EOF 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