mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-11-22 02:17:26 +00:00
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:
parent
c74bef12d2
commit
168c06939d
@ -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
|
||||
# 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 {
|
||||
curl -6 --fail --silent icanhazip.com 2>/dev/null
|
||||
}
|
||||
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 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
|
||||
}
|
||||
target=8.8.8.8
|
||||
|
||||
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
|
||||
}
|
||||
# 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_ipv4 {
|
||||
# helper for get_publicip_fallback
|
||||
[[ "$1" == *.*.*.* ]]
|
||||
}
|
||||
|
||||
function is_ipv6 {
|
||||
[[ "$1" == *:*:* ]]
|
||||
}
|
||||
|
||||
function is_loopback_ip {
|
||||
# helper for get_publicip_fallback
|
||||
[[ "$1" == 127.* ]]
|
||||
}
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user