blob: 90447cd443b632483e43fad17dd78d27b5206ccf [file] [log] [blame]
#!/bin/bash
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This script takes a network interface (eg: tap0) as its only argument. It sets
# up that interface for running a Fuchsia device. It runs dnsmasq to provide
# DHCP and DNS to the Fuchsia device. It configures NAT. It will do its best to
# kill old instances of dnsmasq from previous runs of the script for this
# interface.
#
# It can be passed with -u as a start-up script to run-zircon-* or frun to
# bring up a network for a new qemu instance
#
# If the environment variable FUCHSIA_IP is set it will give that IP to the
# Fuchsia device, otherwise, for historical reasons it will allocate
# 192.168.3.53.
set -eo pipefail; [[ "$TRACE" ]] && set -x
INTERFACE=$1
LEASE_FILE=/tmp/fuchsia-dhcp-$INTERFACE.leases
PID_FILE=/tmp/fuchsia-dhcp-$INTERFACE.pid
LOG_FILE=/tmp/fuchsia-dhcp-$INTERFACE.log
if [[ -z "$INTERFACE" ]]
then
echo "Missing interface name."
exit 1
fi
FUCHSIA_IP=${FUCHSIA_IP:-192.168.3.53} # is this a good default?
if [[ ! $FUCHSIA_IP =~ (^[0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+$ ]]
then
echo "Invalid FUCHSIA_IP '$FUCHSIA_IP'. Must be a valid IPv4 address."
exit 1
fi
SUBNET_PREFIX=${BASH_REMATCH[1]}
FUCHSIA_NETWORK=${SUBNET_PREFIX}.0/24
HOST_IP=${SUBNET_PREFIX}.1
DARWIN=false
if [[ $(uname -s) == Darwin ]]
then
DARWIN=true
fi
# Find the dnsmasq binary.
DNSMASQ=$(which dnsmasq) || DNSMASQ=$(brew --prefix)/sbin/dnsmasq
if [[ ! -x "$DNSMASQ" ]]
then
echo "dnsmasq not found."
if $DARWIN
then
echo " brew install dnsmasq"
else
echo " apt-get install dnsmasq"
fi
exit 1
fi
if [[ $DARWIN == false && $(pidof NetworkManager) ]]
then
nmstat=$(nmcli d status | awk "/$INTERFACE / { print \$3 }")
if [[ -n $nmstat && $nmstat != unmanaged ]]; then
echo "$INTERFACE is managed by NetworkManager so can't be configured by this script."
echo ""
echo "If you DON'T want this, create a file /etc/network/interfaces.d/$INTERFACE.conf containing:"
echo "iface $INTERFACE inet manual"
echo ""
echo "Then restart Network manager with: sudo killall NetworkManager"
exit 1
fi
fi
# Check if dnsmasq is running.
if [[ -r $PID_FILE ]]
then
# Read the PID file.
DNSMASQ_PID=$(<$PID_FILE)
# Check that the PID file actually refers to a dnsmasq process.
if $DARWIN
then
DNSMASQ_PID_NAME=$( (ps -A -o comm $DNSMASQ_PID || true) | tail +2)
if [[ "$DNSMASQ_PID_NAME" != "$DNSMASQ" ]]
then
# There's a PID file but the process name isn't right.
unset DNSMASQ_PID
fi
else
if [[ /proc/$DNSMASQ_PID/exe -ef $DNSMASQ ]]
then
# There's a PID file but the process name isn't right.
unset DNSMASQ_PID
fi
fi
if [[ -n "$DNSMASQ_PID" ]]
then
echo "Killing the old dnsmasq (pid: $DNSMASQ_PID)..."
sudo kill $DNSMASQ_PID || true
sudo rm -f $PID_FILE
fi
fi
if [[ -f "$LEASE_FILE" ]]
then
echo "Removing the old dnsmasq lease file $LEASE_FILE ..."
sudo rm $LEASE_FILE
fi
# Bring up the network.
echo "Bringing up the network interface: $INTERFACE"
sudo ifconfig $INTERFACE inet $HOST_IP
if $DARWIN
then
LOOPBACK=lo0
else
LOOPBACK=lo
fi
echo Starting dnsmasq...
# TODO: can we use --dhcp-host instead of --dhcp-range
sudo $DNSMASQ \
--conf-file=/dev/null \
--bind-interfaces \
--interface=$INTERFACE \
--except-interface=$LOOPBACK \
--dhcp-range=$INTERFACE,$FUCHSIA_IP,$FUCHSIA_IP,24h \
--dhcp-leasefile=$LEASE_FILE \
--pid-file=$PID_FILE \
--log-facility=$LOG_FILE \
--listen-address=$HOST_IP
if $DARWIN
then
# OSX will not bring up ipv6 until an ipv6 address is assigned, but as soon
# as an address is assigned, it will also assign a link-local address. Here
# we assign the same address as used by the zircon ifup script, and let OSX
# assign the link-local address. Previously we computed and assigned a
# link-local address, but this resulted in duplicate addresses assigned to
# the interface, and TAP just duplicated that traffic to applications.
# This is configured after dnsmasq is started, as dnsmasq has no need to
# listen on ipv6, and fails to bind fc00.
sudo ifconfig $INTERFACE inet6 fc00::/7 up
DEFAULT_INTERFACE=$(route -n get default | awk '/interface:/ { print $2 }') || true
else
DEFAULT_INTERFACE=$(ip route get 8.8.8.8 | awk '/^8.8.8.8/ { print $5 }')
fi
if [[ -z "$DEFAULT_INTERFACE" ]]
then
echo "No default route, not enabling forwarding."
else
echo "Enable IP forwarding..."
if $DARWIN
then
sudo sysctl -q net.inet.ip.forwarding=1
echo "
nat on $DEFAULT_INTERFACE from $FUCHSIA_NETWORK to any -> ($DEFAULT_INTERFACE)
pass out on $DEFAULT_INTERFACE inet from $FUCHSIA_NETWORK to any
" | sudo pfctl -q -ef - >& /dev/null || true
else
sudo /bin/bash -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo iptables -t nat -A POSTROUTING -o $DEFAULT_INTERFACE -j MASQUERADE
sudo iptables -A FORWARD -i $DEFAULT_INTERFACE -o $INTERFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i $INTERFACE -o $DEFAULT_INTERFACE -j ACCEPT
fi
fi