Commit 70bd96f6 authored by Joshua Tauberer's avatar Joshua Tauberer

Merge pull request #70 from mkropat/ipv6-support

Support dual-stack IPv4/IPv6 mail servers
parents cd1802fe fb957d2d
...@@ -19,6 +19,7 @@ Vagrant.configure("2") do |config| ...@@ -19,6 +19,7 @@ Vagrant.configure("2") do |config|
# subdomain on our justtesting.email domain so we can get # subdomain on our justtesting.email domain so we can get
# started quickly. # started quickly.
export PUBLIC_IP=auto export PUBLIC_IP=auto
export PUBLIC_IPV6=auto
export PUBLIC_HOSTNAME=auto-easy export PUBLIC_HOSTNAME=auto-easy
export CSR_COUNTRY=US export CSR_COUNTRY=US
......
...@@ -60,9 +60,13 @@ def build_zone(domain, env): ...@@ -60,9 +60,13 @@ def build_zone(domain, env):
records.append((None, "NS", "ns1.%s." % env["PUBLIC_HOSTNAME"])) records.append((None, "NS", "ns1.%s." % env["PUBLIC_HOSTNAME"]))
records.append((None, "NS", "ns2.%s." % env["PUBLIC_HOSTNAME"])) records.append((None, "NS", "ns2.%s." % env["PUBLIC_HOSTNAME"]))
records.append((None, "A", env["PUBLIC_IP"])) records.append((None, "A", env["PUBLIC_IP"]))
if env.get('PUBLIC_IPV6'):
records.append((None, "AAAA", env["PUBLIC_IPV6"]))
records.append((None, "MX", "10 %s." % env["PUBLIC_HOSTNAME"])) records.append((None, "MX", "10 %s." % env["PUBLIC_HOSTNAME"]))
records.append((None, "TXT", '"v=spf1 mx -all"')) records.append((None, "TXT", '"v=spf1 mx -all"'))
records.append(("www", "A", env["PUBLIC_IP"])) records.append(("www", "A", env["PUBLIC_IP"]))
if env.get('PUBLIC_IPV6'):
records.append(("www", "AAAA", env["PUBLIC_IPV6"]))
# In PUBLIC_HOSTNAME, also define ns1 and ns2. # In PUBLIC_HOSTNAME, also define ns1 and ns2.
if domain == env["PUBLIC_HOSTNAME"]: if domain == env["PUBLIC_HOSTNAME"]:
......
...@@ -39,11 +39,19 @@ function get_default_publicip { ...@@ -39,11 +39,19 @@ function get_default_publicip {
get_publicip_from_web_service || get_publicip_fallback get_publicip_from_web_service || get_publicip_fallback
} }
function get_default_publicipv6 {
get_publicipv6_from_web_service || get_publicipv6_fallback
}
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 --fail --silent icanhazip.com 2>/dev/null 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 { function get_publicip_fallback {
...@@ -53,17 +61,39 @@ function get_publicip_fallback { ...@@ -53,17 +61,39 @@ function get_publicip_fallback {
# have multiple addresses if it has multiple network adapters. # have multiple addresses if it has multiple network adapters.
set -- $(hostname --ip-address 2>/dev/null) \ set -- $(hostname --ip-address 2>/dev/null) \
$(hostname --all-ip-addresses 2>/dev/null) $(hostname --all-ip-addresses 2>/dev/null)
while (( $# )) && is_loopback_ip "$1"; do 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 shift
done done
printf '%s\n' "$1" # return this value printf '%s\n' "$1" # return this value
} }
function is_ipv4 {
# helper for get_publicip_fallback
[[ "$1" == *.*.*.* ]]
}
function is_ipv6 {
[[ "$1" == *:*:* ]]
}
function is_loopback_ip { function is_loopback_ip {
# helper for get_publicip_fallback # helper for get_publicip_fallback
[[ "$1" == 127.* ]] [[ "$1" == 127.* ]]
} }
function is_loopback_ipv6 {
[[ "$1" == ::1 ]]
}
function ufw_allow { function ufw_allow {
if [ -z "$DISABLE_FIREWALL" ]; then if [ -z "$DISABLE_FIREWALL" ]; then
# ufw has completely unhelpful output # ufw has completely unhelpful output
......
...@@ -24,6 +24,11 @@ fi ...@@ -24,6 +24,11 @@ fi
# Gather information from the user about the hostname and public IP # Gather information from the user about the hostname and public IP
# address of this host. # address of this host.
if [ -z "$PUBLIC_HOSTNAME" ]; then if [ -z "$PUBLIC_HOSTNAME" ]; then
if [ -z "$DEFAULT_PUBLIC_HOSTNAME" ]; then
# set a default on first run
DEFAULT_PUBLIC_HOSTNAME=`get_default_hostname`
fi
echo echo
echo "Enter the hostname you want to assign to this machine." echo "Enter the hostname you want to assign to this machine."
echo "We've guessed a value. Just backspace it if it's wrong." echo "We've guessed a value. Just backspace it if it's wrong."
...@@ -31,27 +36,35 @@ if [ -z "$PUBLIC_HOSTNAME" ]; then ...@@ -31,27 +36,35 @@ if [ -z "$PUBLIC_HOSTNAME" ]; then
echo "be similar." echo "be similar."
echo echo
if [ -z "$DEFAULT_PUBLIC_HOSTNAME" ]; then
# set a default on first run
DEFAULT_PUBLIC_HOSTNAME=`get_default_hostname`
fi
read -e -i "$DEFAULT_PUBLIC_HOSTNAME" -p "Hostname: " PUBLIC_HOSTNAME read -e -i "$DEFAULT_PUBLIC_HOSTNAME" -p "Hostname: " PUBLIC_HOSTNAME
fi fi
if [ -z "$PUBLIC_IP" ]; then if [ -z "$PUBLIC_IP" ]; then
if [ -z "$DEFAULT_PUBLIC_IP" ]; then
# set a default on first run
DEFAULT_PUBLIC_IP=`get_default_publicip`
fi
echo echo
echo "Enter the public IP address of this machine, as given to" echo "Enter the public IP address of this machine, as given to"
echo "you by your ISP. We've guessed a value, but just backspace" echo "you by your ISP. We've guessed a value, but just backspace"
echo "it if it's wrong." echo "it if it's wrong."
echo echo
if [ -z "$DEFAULT_PUBLIC_IP" ]; then read -e -i "$DEFAULT_PUBLIC_IP" -p "Public IP: " PUBLIC_IP
fi
if [ -z "$PUBLIC_IPV6" ]; then
if [ -z "$DEFAULT_PUBLIC_IPV6" ]; then
# set a default on first run # set a default on first run
DEFAULT_PUBLIC_IP=`get_default_publicip` DEFAULT_PUBLIC_IPV6=`get_default_publicipv6`
fi fi
read -e -i "$DEFAULT_PUBLIC_IP" -p "Public IP: " PUBLIC_IP echo
echo "(Optional) Enter the IPv6 address of this machine. Leave blank"
echo " if the machine does not have an IPv6 address."
read -e -i "$DEFAULT_PUBLIC_IPV6" -p "Public IPv6: " PUBLIC_IPV6
fi fi
if [ -z "$CSR_COUNTRY" ]; then if [ -z "$CSR_COUNTRY" ]; then
...@@ -70,12 +83,17 @@ if [ -z "$CSR_COUNTRY" ]; then ...@@ -70,12 +83,17 @@ if [ -z "$CSR_COUNTRY" ]; then
fi fi
# Automatic configuration, e.g. as used in our Vagrant configuration. # Automatic configuration, e.g. as used in our Vagrant configuration.
if [ "$PUBLIC_IP" == "auto" ]; then if [ "$PUBLIC_IP" = "auto" ]; then
# Use a public API to get our public IP address. # Use a public API to get our public IP address.
PUBLIC_IP=`get_default_publicip` PUBLIC_IP=`get_default_publicip`
echo "IP Address: $PUBLIC_IP" echo "IP Address: $PUBLIC_IP"
fi fi
if [ "$PUBLIC_HOSTNAME" == "auto-easy" ]; then if [ "$PUBLIC_IPV6" = "auto" ]; then
# Use a public API to get our public IP address.
PUBLIC_IPV6=`get_default_publicipv6`
echo "IPv6 Address: $PUBLIC_IPV6"
fi
if [ "$PUBLIC_HOSTNAME" = "auto-easy" ]; then
# Generate a probably-unique subdomain under our justtesting.email domain. # Generate a probably-unique subdomain under our justtesting.email domain.
PUBLIC_HOSTNAME=m`get_default_publicip | sha1sum | cut -c1-5`.justtesting.email PUBLIC_HOSTNAME=m`get_default_publicip | sha1sum | cut -c1-5`.justtesting.email
echo "Public Hostname: $PUBLIC_HOSTNAME" echo "Public Hostname: $PUBLIC_HOSTNAME"
...@@ -97,6 +115,7 @@ cat > /etc/mailinabox.conf << EOF; ...@@ -97,6 +115,7 @@ cat > /etc/mailinabox.conf << EOF;
STORAGE_ROOT=$STORAGE_ROOT STORAGE_ROOT=$STORAGE_ROOT
PUBLIC_HOSTNAME=$PUBLIC_HOSTNAME PUBLIC_HOSTNAME=$PUBLIC_HOSTNAME
PUBLIC_IP=$PUBLIC_IP PUBLIC_IP=$PUBLIC_IP
PUBLIC_IPV6=$PUBLIC_IPV6
CSR_COUNTRY=$CSR_COUNTRY CSR_COUNTRY=$CSR_COUNTRY
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