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
This commit is contained in:
Joshua Tauberer 2014-07-29 19:24:10 -04:00
parent c74bef12d2
commit 168c06939d
3 changed files with 67 additions and 51 deletions

View file

@ -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
######################################################################## ########################################################################
def write_nsd_conf(zonefiles): def write_nsd_conf(zonefiles, env):
# Basic header. # Basic header.
nsdconf = """ nsdconf = """
server: 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 += """

View file

@ -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
# what type of address to get (IPv4, IPv6).
curl -$1 --fail --silent icanhazip.com 2>/dev/null
} }
function get_publicipv6_from_web_service { function get_default_privateip {
curl -6 --fail --silent icanhazip.com 2>/dev/null # 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 get_publicip_fallback { target=8.8.8.8
# 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 { # For the IPv6 route, use the corresponding IPv6 address
set -- $(hostname --ip-address 2>/dev/null) \ # of Google Public DNS. Again, it doesn't matter so long
$(hostname --all-ip-addresses 2>/dev/null) # as it's an address on the public Internet.
while (( $# )) && { ! is_ipv6 "$1" || is_loopback_ipv6 "$1"; }; do if [ "$1" == "6" ]; then target=2001:4860:4860::8888; fi
shift
done
printf '%s\n' "$1" # return this value
}
function is_ipv4 { ip -$1 -o route get $target \
# helper for get_publicip_fallback | grep -v unreachable \
[[ "$1" == *.*.*.* ]] | sed "s/.* src \([^ ]*\).*/\1/"
}
function is_ipv6 {
[[ "$1" == *:*:* ]]
}
function is_loopback_ip {
# helper for get_publicip_fallback
[[ "$1" == 127.* ]]
}
function is_loopback_ipv6 {
[[ "$1" == ::1 ]]
} }
function ufw_allow { function ufw_allow {

View file

@ -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
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