| #!/bin/bash |
| # Copyright 2021 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 is an upscript to use with qemu. It creates a bridge device that |
| # connects to the qemu network interfaces and sets up network forwarding. |
| # The emulator is exposed to the internet, and there is no security |
| # implemented, so should be used with care. |
| # |
| # Example usage with the Fuchsia emulator: |
| # The -I can be any device name, this script creates br${INTERFACE}. |
| # |
| # To use this script with `ffx emu`, configure this file to be |
| # the upscript by running: |
| # ffx config set emu.upscript $FUCHSIA_ROOT/scripts/start-unsecure-internet.sh |
| # |
| # This script is designed to be invoked from qemu with an interface argument. |
| # It can also be run directly for testing as: |
| # scripts/start-unsecure-internet.sh <interface> |
| # |
| # If a --cleanup argument is provided instead of <interface>, this |
| # script will remove the previously created bridge device. |
| |
| usage() { |
| echo "Usage: $(basename "$0") <interface>" |
| echo " [--cleanup]" |
| echo " Remove previously created bridge device and stop" |
| echo " <interface>" |
| echo " Interface name typically 'qemu'" |
| } |
| |
| |
| # Check that we do not run this script in unsupported environments |
| if [[ "$(lsb_release --release --short)" == "rodete" ]]; then |
| echo "This script cannot be run on rodete" |
| exit 1 |
| fi |
| if [[ "$(hostname --fqdn)" == *".google.com" ]]; then |
| echo "This script cannot be run on *.google.com" |
| exit 1 |
| fi |
| |
| |
| CLEANUP=0 |
| if [[ "$1" == "--cleanup" ]]; then |
| CLEANUP=1 |
| shift |
| fi |
| if [[ $1 == -* ]]; then |
| echo "Unknown argument provided" |
| usage |
| exit 1 |
| fi |
| if [[ "$2" != "" ]]; then |
| echo "Unexpected arguments provided" |
| echo |
| usage |
| exit 1 |
| fi |
| |
| INTERFACE="$1" |
| if [[ "${INTERFACE}" == "" ]]; then |
| echo "No network interface name provided by qemu -u" |
| echo |
| usage |
| exit 1 |
| fi |
| BRIDGE="br${INTERFACE}" |
| |
| # Enable error checking for all commands |
| err_print() { |
| echo "Error at $1" |
| stty sane |
| } |
| trap 'err_print $0:$LINENO' ERR |
| set -eu |
| |
| # Show every command being executed |
| set -x |
| |
| # qemu has already brought up ${INTERFACE}, but delete any previous ${BRIDGE} to start from a known state. |
| # If any other interface is using the 172.16.243.1 address, everything will fail silently. |
| sudo ip link delete "${BRIDGE}" || echo "No existing bridge ${BRIDGE} to delete" |
| sudo iptables -D POSTROUTING -t nat -s 172.16.243.0/24 ! -d 172.16.243.0/24 -j MASQUERADE || echo "No existing POSTROUTING nat rule to delete" |
| for delbridge in $(ip --oneline address show to "172.16.243.1" | awk '{ print $2 }'); do |
| sudo ip link delete "${delbridge}" |
| done |
| |
| # Exit out if the purpose was just to clean up |
| if (( CLEANUP )); then |
| exit 0 |
| fi |
| |
| # Enable packet forwarding |
| sudo sysctl -w net.ipv4.ip_forward=1 |
| CHECK="$(cat /proc/sys/net/ipv4/ip_forward)" |
| if [[ "${CHECK}" != "1" ]]; then |
| echo "ERROR: Could not enable ip_forward" |
| exit 1 |
| fi |
| |
| # Create bridge with DHCP and default gateway. |
| sudo ip link add name "${BRIDGE}" type bridge |
| sudo ip addr add 172.16.243.1/24 dev "${BRIDGE}" |
| |
| # UFW blocks DHCP/BOOTP and bridge traffic, so open this up if installed |
| if (command -v ufw && grep -q "^ENABLED=yes" /etc/ufw/ufw.conf) >/dev/null 2>&1; then |
| sudo ufw allow proto udp from 172.16.243.0/24 to 172.16.243.0/24 port 67,68 comment 'Fuchsia qemu DHCP' |
| sudo ufw allow dns comment 'Fuchsia qemu DNS' |
| sudo ufw allow proto udp from 0.0.0.0 to 255.255.255.255 port 67 comment 'Fuchsia qemu DHCP' |
| sudo ufw allow proto udp from 172.16.243.1 to 255.255.255.255 port 68 comment 'Fuchsia qemu DHCP' |
| sudo ufw route allow in on "${BRIDGE}" comment 'Fuchsia qemu bridge in' |
| sudo ufw route allow out on "${BRIDGE}" comment 'Fuchsia qemu bridge out' |
| fi |
| |
| # Remove any previous dnsmasq attached to the IP range we use |
| # Searching for the ${BRIDGE} is another alternative, but it may be different |
| DNSMASQ_PID=$(ps -axww | grep dnsmasq | grep "\-\-dhcp-range=172\.16\.243\.2," | awk '{ print $1 }') |
| if [[ "${DNSMASQ_PID}" != "" ]]; then |
| sudo kill "${DNSMASQ_PID}" |
| fi |
| |
| # I've noticed that --listen-interface= is needed in some situations previously, but doesn't seem to be needed here |
| sudo dnsmasq --interface="${BRIDGE}" --bind-interfaces --dhcp-range=172.16.243.2,172.16.243.254 --except-interface=lo || { echo "Failed to start dnsmasq"; exit 1; } |
| sudo ip link set "${BRIDGE}" up |
| |
| # Remove pre-existing addresses from the interface as they'll no longer be routable |
| sudo ip addr flush "${INTERFACE}" |
| |
| # Add qemu to the bridge |
| sudo ip link set "${INTERFACE}" master "${BRIDGE}" |
| |
| # NAT packets arriving to the bridge |
| sudo iptables -A POSTROUTING -t nat -s 172.16.243.0/24 ! -d 172.16.243.0/24 -j MASQUERADE |