Appendix B. Scripts and Code for QEMU Lab

Table of Contents

The listing below shows how the scripts are organized on the GitHub ipfw-primer/SCRIPTS site.

.
|-- VM_SCRIPTS
|   |-- IPFW_root_bin.tgz                   : common scripts for all VMs (see bin list)
|   |-- Manifest_IPFW_root_bin.txt          : Manifest document for IPFW_root_bin.tgz
|   |-- Manifest_index.txt                  : Manifest document for index.html files
|-- bin
|   |-- tcon.sh                             : TCP connection script
|   |-- tconr.sh                            : TCP connect with random port script
|   |-- tcont.sh                            : TCP continuous connection script
|   |-- tserv.sh                            : TCP server script for one port
|   |-- tserv3.sh                           : TCP server script for three ports
|   |-- ucon.sh                             : UDP connection script
|   |-- uconr.sh                            : UDP connect with random port script
|   |-- ucont.sh                            : UDP continuous connection script
|   |-- userv.sh                            : UDP server script for one port
|   |-- userv3.sh                           : UDP server script for three ports
|   `-- userv5.sh                           : UDP server script for five ports
|   |-- dnshost                             :
|   |   |-- Manifest_namedb.txt             : Manifest for dnshost /usr/local/etc/namedb
|   |   |-- dnshost_usrlocaletc_namedb.tgz  : Files for the above
|   |   `-- index.html                      : Nginx index.html file for dnshost VM
|   |-- external1                           :
|   |   `-- index.html                      : Nginx index.html file for external1 VM
|   |-- external2                           :
|   |   `-- index.html                      : Nginx index.html file for external2 VM
|   |-- external3                           :
|   |   `-- index.html                      : Nginx index.html file for external3 VM
|   |-- firewall                            :
|   |   |-- bsdclat464.sh                   : Script for Section 6.2 XLAT464 CLAT
|   |   `-- index.html                      : Nginx index.html file for firewall VM
|   |-- firewall2                           :
|   |   |-- bsdplat464.sh                   : Script for Section 6.2 XLAT464 CLAT
|   |   `-- index.html                      : Nginx index.html file for firewall2 VM
|   |-- internal                            :
|   |   `-- index.html                      : Nginx index.html file for internal VM
|   `-- v6only                              :
|       `-- index.html                      : Nginx index.html file for v6only VM
|-- _CreateAllVMs.sh                        : Script to create all VMs used in book
|-- dnshost.sh                              : QEMU startup script for dnshost VM
|-- external1.sh                            : QEMU startup script for external1 VM
|-- external2.sh                            : QEMU startup script for external2 VM
|-- external3.sh                            : QEMU startup script for external3 VM
|-- firewall.sh                             : QEMU startup script for firewall VM
|-- firewall2.sh                            : QEMU startup script for firewall2 VM
|-- internal.sh                             : QEMU startup script for internal VM
|-- mkbr.sh                                 : Script to make host bridge and tap devices
|-- runvm.sh                                : XFCE4 script to start VMs
|-- v6only.sh                               : QEMU startup script for v6only VM
|-- vm_envs.sh                              : IPFW lab environment variables
`-- CODE
    `-- divert.c                            : C code for working with divert keyword

All scripts are shown below in lexicographic order:

SCRIPT: VM_SCRIPTS/firewall/bsdclat464.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD 464XLAT CLAT script for firewall VM.
#
# bsdclat464.sh: FreeBSD IPFW script for 464XLAT CLAT.  See Section 6.2
# Usage: # /bin/sh bsdclat464.sh    (run script as root)

set -x

kldunload ipfw_nat64
kldunload ipfw
sleep 1
kldload ipfw
kldload ipfw_nat64

# Create the nat64clat instance
ipfw nat64clat CLAT create clat_prefix 2001:db8:aaaa::/96 plat_prefix 2001:db8:bbbb::/96 allow_private log

# Allow neighbor discovery
ipfw add 100 allow log icmp6 from any to any icmp6types 135,136

# pass any ip through the nat64clat instance
ipfw add 150 nat64clat CLAT log ip from any to any

# pass any ip through the nat64plat instance
ipfw add 200 nat64clat CLAT log ip from any to 2001:db8:bbbb::/96

# allow ipv6 from any to any
ipfw add 300 allow log ip6 from any to any

# allow ipv4 from any to any
ipfw add 400 allow log ip from any to any

# 0=log with ipfwlog0, 1=log with syslog
sysctl net.inet.ip.fw.verbose=0

sysctl net.inet.ip.fw.nat64_debug=1

# direct output: 1 enable, 0 disable (packet goes back into ruleset)
sysctl net.inet.ip.fw.nat64_direct_output=1


==========================================================


SCRIPT: VM_SCRIPTS/firewall2/bsdplat464.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD 464XLAT PLAT script for firewall2 VM.
#
# bsdplat464.sh: FreeBSD IPFW script for 464XLAT CLAT.  See Section 6.2
# Usage: # /bin/sh bsdplat464.sh    (run script as root)

set -x

kldunload ipfw_nat64
kldunload ipfw

sleep 1

kldload ipfw
kldload ipfw_nat64

# create the nat64 stateful instance
ipfw nat64lsn NAT64 create log prefix4 203.0.112.0/24 prefix6 2001:db8:bbbb::/96 allow_private

# Allow neighbor discovery
ipfw add allow log icmp6 from any to any icmp6types 135,136

# Allow the nat64 outbound
ipfw add nat64lsn NAT64 log ip from 2001:db8:12::/64 to 2001:db8:bbbb::/96 in

ipfw add nat64lsn NAT64 log ip from any to 2001:db8:bbbb::/96 in

# Allow the nat64 inbound
ipfw add nat64lsn NAT64  log ip from any to 203.0.112.0/24 in

# Allow ipv4 from any to any
ipfw add allow log ip from any to any

# Allow ipv6 from any to any
ipfw add allow log ip6 from any to any

# Logging: 0 interfaces, 1 syslog
sysctl net.inet.ip.fw.verbose=0

# Debug nat64
sysctl net.inet.ip.fw.nat64_debug=1

# Direct output: 1 enable, 0 disable (packet goes  back into ruleset)
sysctl net.inet.ip.fw.nat64_direct_output=1


==========================================================


SCRIPT: _CreateAllVMs.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# _CreateAllVM.sh : Create VMs for the IPFW Primer lab.  Files are created in ../VM/
#

echo "Running _CreateAllVMs.sh"

echo
echo "This script will create 8 virtual machines in ../VM/"
echo
read -p "DO YOU REALLY WANT TO CREATE NEW QEMU IMAGES OVERWRITING ANY EXISTING IMAGES? Answer YES to continue. " junk
echo [${junk}]

if [ "X${junk}" !=  "XYES" ]
then
  echo "Response was [${junk}]"
  echo "bailing out..."
  exit 1
fi

echo "Response was [${junk}]"
echo "Ok, continuing..."

#exit


for i in dnshost external1 external2 external3 firewall firewall2 internal v6only
do
  echo "Creating ${i} VM"
  echo qemu-img create -f qcow2 -o preallocation=full ../VM/${i}.qcow2 4G
  qemu-img create -f qcow2 -o preallocation=full ../VM/${i}.qcow2 4G
done

echo
echo "Done."


==========================================================


SCRIPT: tcon.sh


#!/bin/sh
#
# location: external Vms
#
# sh tcon.sh PORTNUM   - start up 1 connection over TCP
#

usage() {
  echo "sh tcon.sh PORTNUM"
  exit 1
}


#echo $#

if [ $# -ne 1 ]
then
  usage
else
  export PORT1=$1
fi

# echo "PORT1 = [$PORT1]"

export CONN="203.0.113.50"
export COUNT=1

export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'
export MYNAME="external1"

echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat $CONN $PORT1

export PREVIOUS_PORT=$PORT1

while :
do

  COUNT=expr $COUNT + 1

  read -p "ncat [$COUNT] ready. Enter a valid PORTNUM:  " PORT1

  if [ "X$PORT1" = "X" ]
    then
      PORT1=$PREVIOUS_PORT
  fi

  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat  $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "TCP connection [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  PREVIOUS_PORT=$PORT1

done


==========================================================


SCRIPT: tconr.sh

#!/bin/sh
#
# location: external Vms
#
# sh tconr.sh PORTNUM  SLEEPVAL  (randomized port numbers)  - start up 1 connection over TCP
#

usage() {
  echo "sh tconr.sh PORT1NUM  SLEEPVAL  (randomized port numbers)"
  exit 1
}

# echo $#

if [ $# -ne 2 ]
  then
    usage
fi

PORT1=$1
SLEEPVAL=$2

echo "PORT1     = [$PORT1]"
echo "SLEEPVAL = [$SLEEPVAL]"

export CONN="203.0.113.50"
export COUNT=1
export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'
export MYNAME="external1"

echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat  $CONN $PORT1

while :
do

COUNT=expr $COUNT + 1

# use jot(1) to get a random port between 5656 and 5659.
# Connection to 5659 has no listener on firewall and will thus fail.

  PORT1=jot -r 1 5656 5659 $RANDOM

  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat  $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "TCP connection [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  sleep $SLEEPVAL

done


==========================================================


SCRIPT: tcont.sh

#!/bin/sh
#
# location: external Vms
#
# sh tcont.sh PORT1NUM SLEEPVAL  - keep hammering same TCP port every SLEEPVAL
#

usage() {
  echo "sh tcont.sh PORT1NUM  SLEEPVAL"
  exit 1
}

#echo $#

if [ $# -ne 2 ]
  then
    usage
fi


export PORT1=$1
export SLEEPVAL=$2

echo "PORT1     = [$PORT1]"
echo "SLEEPVAL = [$SLEEPVAL]"

export CONN="203.0.113.50"
export COUNT=1
export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'



echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat  $CONN $PORT1

while :
do

  COUNT=expr $COUNT + 1

  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"
  echo "TCP connection from [$MYIP],[$PORT1],[$COUNT]"| ncat  $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "TCP connection [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  sleep $SLEEPVAL

done


==========================================================


SCRIPT: tserv.sh

#!/bin/sh
#
# location: firewall VMs
#
# tserv.sh - start up 1 listener over TCP

zapall() {
kill -TERM $PID1
}

trap zapall SIGINT


export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'

export PORT1=5656

echo "Starting TCP listener on [$PORT1]"

ncat -l -4 -k $MYIP $PORT1 &
PID1=$!

wait

exit


==========================================================


SCRIPT: tserv3.sh

#!/bin/sh
#
# location: firewall VMs
#
# tserv3.sh - start up 3 listeners over TCP

zapall() {
kill -TERM $PID1 $PID2 $PID3
}

trap zapall SIGINT


export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'

export PORT1=5656
export PORT2=5657
export PORT3=5658

echo "Starting TCP listeners on [$PORT1],[$PORT2],[$PORT3]"

ncat -l -4 -k  $MYIP $PORT1 &
PID1=$!

ncat -l -4 -k  $MYIP $PORT2 &
PID2=$!

ncat -l -4 -k  $MYIP $PORT3 &
PID3=$!

wait

exit


==========================================================


SCRIPT: ucon.sh

#!/bin/sh
#
# location: external Vms
#
# sh ucon.sh PORTNUM   - start up 1 transfer over UDP
#

usage() {
  echo "sh ucon.sh PORTNUM"
  exit 1
}

#echo $#

if [ $# -ne 1 ]
then
  usage
else
  export PORT1=$1
fi

# echo "PORT1 = [$PORT1]"

export CONN="203.0.113.50"
# export CONN="10.10.10.50"
export COUNT=1

export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'
export MYNAME="external1"

echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u $CONN $PORT1

export PREVIOUS_PORT=$PORT1

while :
do

  COUNT=expr $COUNT + 1

  read -p "ncat [$COUNT] ready. Enter a valid PORTNUM:  " PORT1

  if [ "X$PORT1" = "X" ]
    then
      PORT1=$PREVIOUS_PORT
  fi

  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "UDP packet [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  PREVIOUS_PORT=$PORT1

done


==========================================================


SCRIPT: uconr.sh

#!/bin/sh
#
# location: external Vms
#

usage() {
  echo "sh uconr.sh PORT1NUM  SLEEPVAL  (randomized port numbers)"
  exit 1
}


# echo $#

if [ $# -ne 2 ]
  then
    usage
fi


PORT1=$1
SLEEPVAL=$2


echo "PORT1     = [$PORT1]"
echo "SLEEPVAL = [$SLEEPVAL]"



export CONN="203.0.113.50"
export COUNT=1
export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'
export MYNAME="external1"


echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u  $CONN $PORT1

while :
do

COUNT=expr $COUNT + 1

# use jot(1) to get a random port between 5656 and 5659.
# Packet on 5659 has no listener on firewall and will thus fail.

  PORT1=jot -r 1 5656 5659 $RANDOM

  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "UDP packet [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  sleep $SLEEPVAL

done


==========================================================


SCRIPT: ucont.sh

#!/bin/sh
#
# location: external Vms
#
# sh ucont.sh PORT1NUM SLEEPVAL  - keep hammering same UDP port every SLEEPVAL
#

usage() {
  echo "sh ucont.sh PORT1NUM  SLEEPVAL"
  exit 1
}

#echo $#

if [ $# -ne 2 ]
  then
    usage
fi


export PORT1=$1
export SLEEPVAL=$2

echo "PORT1     = [$PORT1]"
echo "SLEEPVAL = [$SLEEPVAL]"

# export CONN="10.10.10.50"
export CONN="203.0.113.50"
export COUNT=1
export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'

echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u  $CONN $PORT1

while :
do

  COUNT=expr $COUNT + 1

#  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
#  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u $CONN $PORT1

  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"
  echo "UDP packet from [$MYIP],[$PORT1],[$COUNT]"| ncat -u $CONN $PORT1

  if [ $? -ne 0 ]
  then
    echo  "UDP packet [$MYIP],[$PORT1],[$COUNT] FAILED"
  fi

  sleep $SLEEPVAL

done


==========================================================


SCRIPT: userv.sh

#!/bin/sh
#
# location: firewall VMs
#
# userv.sh PORTNUM   - start up 1 listener over UDP
#

usage() {
  echo "sh userv.sh PORTNUM"
  exit 1
}

#echo $#

if [ $# -ne 1 ]
then
  usage
else
  PORT1=$1
fi

echo "PORT1 = [$PORT1]"

zapall() {
kill -TERM $PID1
}

trap zapall SIGINT

export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'


echo "Starting UDP listener on [$MYIP],[$PORT1]"

# echo nc -l -k -u  $MYIP  $PORT1
nc -l -k -u  $MYIP  $PORT1 &
PID1=$!

wait

exit


==========================================================


SCRIPT: userv3.sh


#!/bin/sh
#
# location: firewall VMs
#
# userv3.sh - start up 3 listeners over udp

zapall() {
kill -TERM $PID1 $PID2 $PID3
}

trap zapall SIGINT


export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'

export PORT1=5656
export PORT2=5657
export PORT3=5658


echo "Starting UDP listeners on [$PORT1],[$PORT2],[$PORT3]"

nc -l -k -u  $MYIP  $PORT1 &
PID1=$!

nc -l -k -u  $MYIP  $PORT2 &
PID2=$!

nc -l -k -u  $MYIP  $PORT3 &
PID3=$!

wait

exit


==========================================================


SCRIPT: userv5.sh

#!/bin/sh
#
# location: firewall VMs
#
# userv5.sh - start up 5 listeners over udp

zapall() {
kill -TERM $PID1 $PID2 $PID3 $PID4 $PID5
}

trap zapall SIGINT


export MYIP=ifconfig em0 | grep inet | grep -v inet6 | awk '{print $2}'
export PORT1=5656
export PORT2=5657
export PORT3=5658
export PORT4=5659
export PORT5=5660


echo "Starting UDP listeners on [$PORT1],[$PORT2],[$PORT3],[$PORT4],[$PORT5]"

nc -l -k -u  $MYIP  $PORT1 &
PID1=$!

nc -l -k -u  $MYIP  $PORT2 &
PID2=$!

nc -l -k -u  $MYIP  $PORT3 &cd
PID3=$!

nc -l -k -u  $MYIP  $PORT4 &
PID4=$!

nc -l -k -u  $MYIP  $PORT5 &
PID5=$!

wait

exit


==========================================================


SCRIPT: dnshost.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for dnshost VM.
#
# dnshost.sh: FreeBSD QEMU VM startup script for dnshost VM.
# Usage: sudo /bin/sh dnshost.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [ISO=${_DNSHOST_ISO}]
echo [mem=${_DNSHOST_mem}]
echo [hdsize=${_DNSHOST_hdsize}]
echo [img=${_DNSHOST_img}]
echo [mac1=${_DNSHOST_mac1}]
echo [mac2=${_DNSHOST_mac2}]
echo [name=${_DNSHOST_name}]
echo [tap7=${_DNSHOST_tap7}]
echo [tap8=${_DNSHOST_tap8}]
echo [tap11=${_DNSHOST_tap11}]
echo [telnetport=${_DNSHOST_telnetport}]

#exit

# Note - the dnshost has two interfaces - em0 and em1.
#        em0 is considered the ipv4 interface and
#        em1 is considered the ipv6 interface.

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_DNSHOST_telnetport"
echo

/usr/local/bin/qemu-system-x86_64  -monitor stdio \
  -serial telnet:localhost:${_DNSHOST_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_DNSHOST_mem}      \
  -cdrom ${_DNSHOST_ISO}  \
  -boot order=cd,menu=on,splash=${_DNS_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_DNSHOST_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_DNSHOST_tap7},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_DNSHOST_mac1} \
  -netdev tap,id=nd1,ifname=${_DNSHOST_tap8},script=no,downscript=no \
  -device e1000,netdev=nd1,mac=${_DNSHOST_mac2} \
  -netdev tap,id=nd2,ifname=${_DNSHOST_tap11},script=no,downscript=no \
  -device e1000,netdev=nd2,mac=${_DNSHOST_mac3} \
  -name \"${_DNSHOST_name}\"


==========================================================


SCRIPT: external1.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for external1 VM.
#
# external1.sh: FreeBSD QEMU VM startup script for external1 VM.
# Usage: sudo /bin/sh external1.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# external1.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [$_EXTERNAL1_ISO]
echo [$_EXTERNAL1_mem]
echo [$_EXTERNAL1_hdsize]
echo [$_EXTERNAL1_img]
echo [$_EXTERNAL1_mac]
echo [$_EXTERNAL1_name]
echo [$_EXTERNAL1_tap1]
echo [$_EXTERNAL1_telnetport]

#
#exit
#

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_EXTERNAL1_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor vc \
  -serial telnet:localhost:${_EXTERNAL1_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_EXTERNAL1_mem}      \
  -cdrom ${_EXTERNAL1_ISO}  \
  -boot order=cd,menu=on,splash=${_EX1_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_EXTERNAL1_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_EXTERNAL1_tap1},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_EXTERNAL1_mac} \
  -name \"${_EXTERNAL1_name}\"


==========================================================


SCRIPT: external2.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for external2 VM.
#
# external2.sh: FreeBSD QEMU VM startup script for external2 VM.
# Usage: sudo /bin/sh external2.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#

# FreeBSD qemu vm startup script
#
# external2.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [ISO=${_EXTERNAL2_ISO}]
echo [mem=${_EXTERNAL2_mem}]
echo [hdsize=${_EXTERNAL2_hdsize}]
echo [img=${_EXTERNAL2_img}]
echo [mac=${_EXTERNAL2_mac}]
echo [name=${_EXTERNAL2_name}]
echo [tap2=${_EXTERNAL2_tap2}]
echo [telnetport=${_EXTERNAL2_telnetport}]

#
#exit
#

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_EXTERNAL2_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor stdio \
  -serial telnet:localhost:${_EXTERNAL2_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_EXTERNAL2_mem}      \
  -cdrom ${_EXTERNAL2_ISO}  \
  -boot order=cd,menu=on,splash=${_EX2_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_EXTERNAL2_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_EXTERNAL2_tap2},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_EXTERNAL2_mac} \
  -name \"${_EXTERNAL2_name}\"


==========================================================


SCRIPT: external3.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for external3 VM.
#
# external3.sh: FreeBSD QEMU VM startup script for external3 VM.
# Usage: sudo /bin/sh external3.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# external3.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [ISO=${_EXTERNAL3_ISO}]
echo [mem=${_EXTERNAL3_mem}]
echo [hdsize=${_EXTERNAL3_hdsize}]
echo [img=${_EXTERNAL3_img}]
echo [mac=${_EXTERNAL3_mac}]
echo [name=${_EXTERNAL3_name}]
echo [tap3=${_EXTERNAL3_tap3}]
echo [telnetport=${_EXTERNAL3_telnetport}]

#
#exit
#


echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_EXTERNAL3_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor vc \
  -serial telnet:localhost:${_EXTERNAL3_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_EXTERNAL3_mem}      \
  -cdrom ${_EXTERNAL3_ISO}  \
  -boot order=cd,menu=on,splash=${_EX3_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_EXTERNAL3_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_EXTERNAL3_tap3},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_EXTERNAL3_mac} \
  -name \"${_EXTERNAL3_name}\"





==========================================================


SCRIPT: firewall.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for firewall VM.
#
# firewall.sh: FreeBSD QEMU VM startup script for firewall VM.
# Usage: sudo /bin/sh firewall.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# firewall.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [$_FIREWALL_ISO]
echo [$_FIREWALL_mem]
echo [$_FIREWALL_hdsize]
echo [$_FIREWALL_img]
echo [$_FIREWALL_mac1]
echo [$_FIREWALL_mac2]
echo [$_FIREWALL_name]
echo [$_FIREWALL_tap0]
echo [$_FIREWALL_tap4]
echo [$_FIREWALL_telnetport]

#exit

# Note - the firewall has two interfaces - em0 and em1.
#        em0 is considered the 'external' interface and
#        em1 is considered the 'internal' interface.

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_FIREWALL_telnetport "
echo

/usr/local/bin/qemu-system-x86_64 -monitor none \
  -serial telnet:localhost:${_FIREWALL_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -display gtk \
  -vga cirrus \
  -m ${_FIREWALL_mem}      \
  -cdrom ${_FIREWALL_ISO}  \
  -boot order=cd,menu=on,splash=${_FW_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_FIREWALL_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_FIREWALL_tap0},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_FIREWALL_mac1} \
  -netdev tap,id=nd1,ifname=${_FIREWALL_tap4},script=no,downscript=no \
  -device e1000,netdev=nd1,mac=${_FIREWALL_mac2} \
  -name \"${_FIREWALL_name}\"


==========================================================


SCRIPT: firewall2.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for firewall2 VM.
#
# firewall2.sh: FreeBSD QEMU VM startup script for firewall2 VM.
# Usage: sudo /bin/sh firewall2.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# firewall2.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh

echo [ISO=${_FIREWALL2_ISO}]
echo [mem=${_FIREWALL2_mem}]
echo [hdsize=${_FIREWALL2_hdsize}]
echo [img=${_FIREWALL2_img}]
echo [mac1=${_FIREWALL2_mac1}]
echo [mac2=${_FIREWALL2_mac2}]
echo [name=${_FIREWALL2_name}]
echo [tap9=${_FIREWALL2_tap9}]
echo [tap10=${_FIREWALL2_tap10}]
echo [telnetport=${_FIREWALL2_telnetport}]

#exit

# Note - the firewall has two interfaces - em0 and em1.
#        em0 is considered the 'external' interface and
#        em1 is considered the 'internal' interface.

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_FIREWALL2_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor none \
  -serial telnet:localhost:${_FIREWALL2_telnetport},server=on,wait=on \
  -cpu qemu64 \
  -display gtk \
  -vga cirrus \
  -m ${_FIREWALL2_mem}      \
  -cdrom ${_FIREWALL_ISO}  \
  -boot order=cd,menu=on,splash=${_FW2_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_FIREWALL2_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_FIREWALL2_tap9},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_FIREWALL2_mac1} \
  -netdev tap,id=nd1,ifname=${_FIREWALL2_tap10},script=no,downscript=no \
  -device e1000,netdev=nd1,mac=${_FIREWALL2_mac2} \
  -name \"${_FIREWALL2_name}\"


==========================================================


SCRIPT: internal.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for internal VM.
#
# internal.sh: FreeBSD QEMU VM startup script for internal VM.
# Usage: sudo /bin/sh internal.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# internal.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh


echo [ISO=${_INTERNAL_ISO}]
echo [mem=${_INTERNAL_mem}]
echo [hdsize=${_INTERNAL_hdsize}]
echo [img=${_INTERNAL_img}]
echo [mac=${_INTERNAL_mac}]
echo [name=${_INTERNAL_name}]
echo [tap5=${_INTERNAL_tap5}]
echo [telnetport=${_INTERNAL_telnetport}]

#
#exit

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_INTERNAL_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor none \
  -serial telnet:localhost:${\_INTERNAL_telnetport},server \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_INTERNAL_mem}      \
  -cdrom ${_INTERNAL_ISO}  \
  -boot order=cd,menu=on,splash=${_INT_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_INTERNAL_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_INTERNAL_tap5},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_INTERNAL_mac} \
  -name \"${_INTERNAL_name}\"


==========================================================


SCRIPT: mkbr.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD startup script for bridge and tap devices.
#
# mkbr.sh: FreeBSD startup script for bridge and tap devices.
# EXAMPLE Usage: sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 bridge1 tap2 bridge2 tap3 tap4 tap5 em0
#
# mkbr.sh - manage bridge and tap interfaces for FreeBSD.
#
# Have fun, but don't blame me if it smokes your machine.
#
# This script is used to start the bridge and tap interfaces.
#
# To create one bridge, two tap interfaces, and connect the
# local ethernet interace (here em0), run under sudo as follows:
#   sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 em0
#
# The script can be used to create any number of  bridges and taps
# for any internal network design:
#   sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 bridge1 tap2 tap3 tap4 bridge2 tap5 em0 ... etc.
#
# To add other taps to existing bridges, do not specify the "reset" parameter.
#   sudo /bin/sh mkbr.sh       bridge0 tap10 tap11  bridge1 tap12 tap13  ... etc.
#
# To delete all bridge and tap devices:
#   sudo /bin/sh mkbr.sh reset
#
#

#set -x


usage() {
   echo "Usage: mkbr.sh  ["reset"] <bridgeN> <tapA> [[<bringeM>] <tapB> <tapC> ...]"
   echo "You must be root to run this script."
   exit 1
}


if [ "X0" != "X`id -u`" ]
then
	  usage
  fi

if [ $# = 0 ]
then
   usage;
fi

if [ $1 = "reset" ]
then
  echo
  echo "Note - if_bridge and/or if_tap may be compiled into the kernel and can't be  unloaded.  Adjust interfaces manually if necessary."
  echo
  echo "unloading..."
  kldunload if_bridge
  kldunload if_tap
  echo
  echo "Deleting any remaining bridge and tap devices:"

  for i in ifconfig -l
  do
    echo "Interface: ${i}"

    case ${i} in

        bridge*)
            echo " ... destroying bridge ${i}"
            ifconfig ${i} destroy
            ;;
        tap*)
            echo " ... destroying tap ${i}"
            ifconfig ${i} destroy
            ;;
    esac
  done

  sleep 1
  echo "loading..."
  kldload if_bridge
  kldload if_tap
  shift
  RESET="Y"
  echo "RESET=Y"
  # Before using the tap devices in QEMU, two sysctls require adjustment:
  sysctl net.link.tap.user_open=1
  sysctl net.link.tap.up_on_open=1
else
  RESET="N"
  echo "RESET=N"
fi


PARAM=$1

while [ "X${PARAM}" != "X" ]
do
#  echo "PARAM=[$PARAM]"

  case $PARAM  in

    bridge*)  BRIDGE=$1

       #  if [ "$RESET" = "Y" ]
       #  then
           echo ifconfig $BRIDGE create
                ifconfig $BRIDGE create
           echo ifconfig $BRIDGE
                ifconfig $BRIDGE
       #  fi
         echo ifconfig $BRIDGE up
              ifconfig $BRIDGE up
         ;;

    tap*)  TAP=$1
       #  if [ "$RESET" = "Y" ]
       #  then
           echo ifconfig $TAP create
                ifconfig $TAP create
       #  fi
         echo "ifconfig $BRIDGE addm $TAP "
               ifconfig $BRIDGE addm $TAP
         ;;

    *)   echo "*** Checking to see if $1 is a valid interface"
         TMPINT=$1
         RESULT="IS NOT"
         for i in ifconfig -l
         do
#           echo $i
           if [ "${i}X" = "${TMPINT}X" ]
           then
              echo "Found a valid interface: ${TMPINT} Adding it to the bridge. Check results."
              echo "ifconfig $BRIDGE addm $TMPINT"
                    ifconfig $BRIDGE addm $TMPINT
              RESULT="IS"
              break;
           else
              echo -n "."
           fi
         done

         echo "Interface ${TMPINT} $RESULT a valid interface."
         ;;
  esac

  shift
  PARAM=$1
done

exit 0


==========================================================


SCRIPT: runvm.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for multiple VMs at once.
#
# runvm.sh: FreeBSD QEMU VM startup script for multiple VMs.
# EXAMPLE Usage: /bin/sh runvm.sh  firewall external1 external2 internal
#
# location: FreeBSD Host
#
#  runvm.sh - run virtual machines specified on the command line.
#
#  To use this script, run mkbr.sh first to set up the bridge and
#  tap configurations for the desired network architecture.
#
# NOTE: this script works best on XFCE4 desktop as it takes advantage of the
#       xfce4-terminal and it's ability to use multiple tabs.
#
#  >>>> It is unlikely to work on another desktop.  <<<<
#
#  Essentially, this script is a big case statement.  It gets the
#  command line names of the virtual machines and calls a function
#  that starts the virtual machine.
#


# pick up environment for this run
. ./vm_envs.sh


#set -x

#WKDIR=$HOME/LAB/SCRIPTS
export WKDIR=$HOME/ipfw

echo "[${WKDIR}]"


usage() {
    echo "Usage: /bin/sh runvm.sh  vmname [vmname ...]"
    echo "Each virtual machine opens up on xfce4-terminal with two tabs -"
    echo "   one for the qemu virtual machine, and one for the serial"
    echo "   terminal interface."
    echo ""
    exit 1
}


CURDIR=pwd

if [ "X${CURDIR}" != "X${WKDIR}/SCRIPTS" ]
then
    usage;
fi


if [ $# = 0 ]
then
   usage;
fi

# Functions for each VM

dnshost_vm () {
  # DNS host
  echo "in function: [${_DNSHOST_telnetport}]"
  xfce4-terminal --window --geometry="80x24+50+50" --zoom="-1" \
               -T "${_DNSHOST_name}" -e "bash -c \"cd ${WKDIR}/SCRIPTS && sudo /bin/sh dnshost.sh ; bash\"" \
        --tab  -T "${_DNSHOST_name}" -e "bash -c \"cd ${WKDIR}/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet -4  localhost ${_DNSHOST_telnetport}); bash\""
  return
}

external1_vm () {
  # external1
  echo "in function: [${_EXTERNAL1_telnetport}]"
  xfce4-terminal --window --geometry="80x24+75+75" --zoom="-1" \
               -T "${_EXTERNAL1_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh external1.sh ; bash\"" \
        --tab  -T "${_EXTERNAL1_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_EXTERNAL1_telnetport}); bash\""
  return
}

external2_vm () {
  # external2
  echo "in function: [${_EXTERNAL2_telnetport}]"
  xfce4-terminal --window --geometry="80x24+100+100" --zoom="-1" \
               -T "${_EXTERNAL2_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh external2.sh ; bash\"" \
        --tab  -T "${_EXTERNAL2_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_EXTERNAL2_telnetport}); bash\""
  return
}

external3_vm () {
  # external3
  echo "in function: [${_EXTERNAL3_telnetport}]"
  xfce4-terminal --window --geometry="80x24+125+125" --zoom="-1" \
               -T "${_EXTERNAL3_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh external3.sh ; bash\"" \
        --tab  -T "${_EXTERNAL3_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_EXTERNAL3_telnetport}); bash\""
  return
}

firewall_vm () {
  # Firewall
  echo "in function: [${_FIREWALL_telnetport}]"
  xfce4-terminal --window --geometry="80x24+150+150" --zoom="-1" \
               -T "${_FIREWALL_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh firewall.sh ; bash\"" \
        --tab  -T "${_FIREWALL_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh; telnet localhost ${_FIREWALL_telnetport}); bash\""
  return
}

firewall2_vm () {
  # Firewall2
  echo "in function: [${_FIREWALL2_telnetport}]"
  xfce4-terminal --window --geometry="80x24+175+175" --zoom="-1" \
               -T "${_FIREWALL2_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh firewall2.sh ; bash\"" \
        --tab  -T "${_FIREWALL2_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_FIREWALL2_telnetport}); bash\""
  return
}

internal_vm () {
  # internal
  echo "in function: [${_INTERNAL_telnetport}]"
  xfce4-terminal --window --geometry="80x24+200+200" --zoom="-1" \
               -T "${_INTERNAL_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh internal.sh ; bash\"" \
        --tab  -T "${_INTERNAL_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_INTERNAL_telnetport}); bash\""
  return
}

v6only_vm () {
  # v6only
  echo "in function: [${_V6ONLY_telnetport}]"
  xfce4-terminal --window --geometry="80x24+225+225" --zoom="-1" \
               -T "${_V6ONLY_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sudo /bin/sh v6only.sh ; bash\"" \
        --tab  -T "${_V6ONLY_name}" -e "bash -c \"cd $WKDIR/SCRIPTS && sleep 2 && (. ./vm_envs.sh;telnet localhost ${_V6ONLY_telnetport}); bash\""
  return
}


#
# Startup the requested VMs
#


PARAM=$1

while [ "X${PARAM}" != "X" ]
do
  echo "PARAM = [${PARAM}]"

  case ${PARAM} in

    dnshost)
        echo "dnshost ..."
	echo "_DNSHOST_telnetport = [${_DNSHOST_telnetport}]"
        dnshost_vm
      ;;

    external1)
        echo "external1 ..."
	echo "_EXTERNAL1_telnetport = [${_EXTERNAL1_telnetport}]"
        external1_vm
      ;;

    external2)
        echo "external2 ..."
	echo "_EXTERNAL2_telnetport = [${_EXTERNAL2_telnetport}]"
        external2_vm
      ;;

    external3)
        echo "external3 ..."
	echo "_EXTERNAL3_telnetport = [${_EXTERNAL3_telnetport}]"
        external3_vm
      ;;

    firewall)
        echo "firewall ..."
	echo "_FIREWALL_telnetport = [${_FIREWALL_telnetport}]"
        firewall_vm
      ;;

    firewall2)
        echo "firewall2 ..."
	echo "_FIREWALL2_telnetport = [${_FIREWALL2_telnetport}]"
        firewall2_vm
      ;;

    internal)
        echo "internal ..."
	echo "_INTERNAL_telnetport = [${_INTERNAL_telnetport}]"
        internal_vm
      ;;

    v6only)
        echo "v6only ..."
	echo "_V6ONLY_telnetport = [${_V6ONLY_telnetport}]"
        v6only_vm
      ;;

    *)
      echo ""
      echo "*** ERROR: NO VM NAMED [$PARAM]"
      echo ""
    ;;

  esac

  shift

  sleep 3

  PARAM=$1
done

exit 0


==========================================================


SCRIPT: v6only.sh

#!/bin/sh
# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM startup script for v6only VM.
#
# v6only.sh: FreeBSD QEMU VM startup script for v6only VM.
# Usage: sudo /bin/sh v6only.sh
# Note: Set up for serial console. Start another session and telnet to the port shown.
#
# FreeBSD QEMU VM startup script
#
# v6only.sh
#
#set -x

# pick up environment for this run
. ./vm_envs.sh


echo  [ISO=${_V6ONLY_ISO}]
echo  [mem=${_V6ONLY_mem}]
echo  [hdsize=${_V6ONLY_hdsize}]
echo  [img=${_V6ONLY_img}]
echo  [mac=${_V6ONLY_mac}]
echo  [name=${_V6ONLY_name}]
echo  [tap6=${_V6ONLY_tap6}]
echo  [telnetport=${_V6ONLY_telnetport}]

#
#exit

echo
echo "NOTE!!! telnet server running!  To start QEMU telnet to localhost $_V6ONLY_telnetport"
echo

/usr/local/bin/qemu-system-x86_64 -monitor none \
  -serial telnet:localhost:${_V6ONLY_telnetport},server \
  -cpu qemu64 \
  -vga cirrus \
  -m ${_V6ONLY_mem}      \
  -cdrom ${_V6ONLY_ISO}  \
  -boot order=cd,menu=on,splash=${_V6_splash},splash-time=3000 \
  -drive if=none,id=drive0,cache=none,aio=threads,format=raw,file=${_V6ONLY_img} \
  -device virtio-blk,drive=drive0  \
  -netdev tap,id=nd0,ifname=${_V6ONLY_tap6},script=no,downscript=no \
  -device e1000,netdev=nd0,mac=${_V6ONLY_mac} \
  -name \"${_V6ONLY_name}\"


==========================================================


SCRIPT: vm_envs.sh

# IPFW Primer
# License: 3-clause BSD
# Author: Jim Brown, jpb@jimby.name
# Code: https://github.com/jimmyb-gh/ipfw-primer
#
# FreeBSD QEMU VM environment script.
#
# vmenv.sh: FreeBSD QEMU VM environment setup script.
# Usage: ./bin/sh vmenv.sh
#
# vm_envs.sh - environment for setting up virtual machines
#              for the IPFW examples lab.
#
# Set the environment variables below (or keep the defaults)
# Note that the default disk size for each virtual machine is
# 4GB - so all five VMs will take up about 32GB if you preallocate
# space.
#
# In brief:
#
#  Install FreeBSD on the host machine and update to latest patch level.
#  Install desktop software.
#  Install QEMU (latest)
#  Install nmap (needed for ncat)
#  Install sudo
#
#
#  The script mkbr.sh should be run before starting
#  the virtual machines.  mkbr.sh sets up the bridge and tap
#  devices needed by the VMs.
#
#  sudo /bin/sh  ./mkbr.sh reset bridge0 tap0 tap1 tap2 tap3 em0 bridge1 tap4 tap5
#
# This will set up the devices needed by QEMU.
#
#
#The file directory layout for the examples is:
#
#    ~/ipfw
#          /SCRIPTS
#              _CreateAllVMs.sh   (create Qemu disks images)
#              dnshost.sh         (run script for dns server VM)
#              external1.sh       (run scripts for external  VMs)
#              external2.sh                  "
#              external3.sh                  "
#              firewall.sh        (run script for firewall VM)
#              firewall2.sh       (run script for firewall2 VM)
#              internal.sh        (script to setup internal host)
#              v6only.sh          (run script for IPv6 only VM)
#              mkbr.sh            (script to create bridge and tap devices)
#              vm_envs.sh         (script to manage all parameters)
#              runvm.sh           (script to manage all virtual machines)
#          /BMP
#              dns_splash_640x480.bmp
#              external1_splash_640x480.bmp
#              external2_splash_640x480.bmp
#              external3_splash_640x480.bmp
#              internal_splash_640x480.bmp
#              ipfw2_splash_640x480.bmp
#              ipfw_splash_640x480.bmp
#              v6only_splash_640x480.bmp
#              dnshost_splash_640x480.bmp
#          /ISO
#              fbsd.iso           (latest FreeBSD install iso)
#          /VM
#              dnshost.qcow2        (Qemu disk image for dns host)
#              external1.qcow2      (Qemu disk image for external hosts)
#              external2.qcow2                  "
#              external3.qcow2                  "
#              firewall.qcow2       (Qemu disk image for firewall)
#              firewall2.qcow2      (Qemu disk image for firewall2)
#              internal.qcow2       (Qemu disk image for an internal host)
#              v6only.qcow2         (Qemu disk image for an ipv6only host)
#
#
#  Start the VMs and install / test one at a time.
#
#    sudo /bin/sh firewall.sh
#    sudo /bin/sh firewall2.sh
#    sudo /bin/sh external1.sh
#    sudo /bin/sh external2.sh
#    sudo /bin/sh external3.sh
#    sudo /bin/sh internal.sh
#    sudo /bin/sh v6only.sh
#    sudo /bin/sh dnshost.sh
#
#  Each install should first utilize DHCP to get a valid IP address
#  After install, proceed to update FreeBSD with "freebsd-update fetch install"
#  Install packages:
#  Use whatever shell you prefer.  Bash is listed below.
#    Firewall   - pkg install bash cmdwatch lynx iperf3 nmap hping3 nginx
#    All others - pkg install bash cmdwatch lynx iperf3 nmap hping3 nginx
#    DNS host   - pkg install bind918  dual-dhclient bash cmdwatch lynx nginx
#
#  Reset all IP addresses for static usage:
#
#  Host interface: add  172.16.10.100/24 alias
#  Disable any firewall (pf, ipfw, etc.) on the host.
#           BE SURE this is Ok for your environment.
#
#  Firewall em0 172.16.10.50/24, default gateway 172.16.10.100
#           em1 10.10.10.50/24
#
#  Firewall2 em0 as needed
#            em1 as needed
#
#  External1: em0 172.16.10.10/24, default gateway 172.16.10.100
#  External2: em0 172.16.10.20/24, default gateway 172.16.10.100
#  External3: em0 172.16.10.30/24, default gateway 172.16.10.100
#  Internal:  em0 10.10.10.200/24, default gateway 10.10.10.50
#
#  v6only  as needed
#  dnshost as needed
#
#

export _BASE=/home/jpb/ipfw

# Bridge and tap info
export _FIREWALL_tap0=tap0
export _EXTERNAL1_tap1=tap1
export _EXTERNAL2_tap2=tap2
export _EXTERNAL3_tap3=tap3
export _FIREWALL_tap4=tap4
export _INTERNAL_tap5=tap5
export _V6ONLY_tap6=tap6
export _DNSHOST_tap7=tap7
export _DNSHOST_tap8=tap8
export _FIREWALL2_tap9=tap9
export _FIREWALL2_tap10=tap10
export _DNSHOST_tap11=tap11

export _bridge0_=bridge0
export bridge1=bridge1
export bridge2=bridge2


# Disk sizes
export _EXTERNAL1_hdsize=4G
export _EXTERNAL2_hdsize=4G
export _EXTERNAL3_hdsize=4G
export _FIREWALL_hdsize=4G
export _FIREWALL2_hdsize=4G
export _INTERNAL_hdsize=4G
export _V6ONLY_hdsize=4G
export _DNSHOST_hdsize=4G

# Is this needed anymore?
export _FBSD_ISO=${_BASE}/ISO/fbsd.iso

# Boot iso locations
export _DNSHOST_ISO=${_BASE}/ISO/fbsd.iso
export _EXTERNAL1_ISO=${_BASE}/ISO/fbsd.iso
export _EXTERNAL2_ISO=${_BASE}/ISO/fbsd.iso
export _EXTERNAL3_ISO=${_BASE}/ISO/fbsd.iso
export _FIREWALL_ISO=${_BASE}/ISO/fbsd.iso
export _FIREWALL2_ISO=${_BASE}/ISO/fbsd.iso
export _INTERNAL_ISO=${_BASE}/ISO/fbsd.iso
export _V6ONLY_ISO=${_BASE}/ISO/fbsd.iso

# Memory sizes
export _DNSHOST_mem=1024
export _EXTERNAL1_mem=1024     # lower all to 512 if necessary
export _EXTERNAL2_mem=1024
export _EXTERNAL3_mem=1024
export _FIREWALL_mem=1024
export _FIREWALL2_mem=1024
export _INTERNAL_mem=1024
export _V6ONLY_mem=1024


# Qemu disk image locations.
export _DNSHOST_img=${_BASE}/VM/dnshost.qcow2
export _EXTERNAL1_img=${_BASE}/VM/external1.qcow2
export _EXTERNAL2_img=${_BASE}/VM/external2.qcow2
export _EXTERNAL3_img=${_BASE}/VM/external3.qcow2
export _FIREWALL_img=${_BASE}/VM/firewall.qcow2
export _FIREWALL2_img=${_BASE}/VM/firewall2.qcow2
export _INTERNAL_img=${_BASE}/VM/internal.qcow2
export _V6ONLY_img=${_BASE}/VM/v6only.qcow2

# MAC addresses
export _DNSHOST_mac1=02:49:53:53:53:53
export _DNSHOST_mac2=02:49:53:53:54:54
export _DNSHOST_mac3=02:49:53:53:55:55
export _EXTERNAL1_mac=02:45:58:54:31:10
export _EXTERNAL2_mac=02:45:58:54:32:20
export _EXTERNAL3_mac=02:45:58:54:33:30
export _FIREWALL_mac1=02:49:50:46:57:41
export _FIREWALL2_mac1=02:49:50:00:22:22
export _FIREWALL_mac2=02:49:50:46:57:42
export _FIREWALL2_mac2=02:49:50:22:22:22
export _INTERNAL_mac=02:49:4E:54:0a:42
export _V6ONLY_mac=02:49:de:ad:be:ef

# VM names
export _DNSHOST_name=DNSHOST
export _EXTERNAL1_name=EXTERNAL1
export _EXTERNAL2_name=EXTERNAL2
export _EXTERNAL3_name=EXTERNAL3
export _FIREWALL_name=FIREWALL
export _FIREWALL2_name=FIREWALL2
export _INTERNAL_name=INTERNAL
export _V6ONLY_name=V6ONLY

# Slash images
export _DNS_splash=${_BASE}/BMP/dns_splash_640x480.bmp
export _EX1_splash=${_BASE}/BMP/external1_splash_640x480.bmp
export _EX2_splash=${_BASE}/BMP/external2_splash_640x480.bmp
export _EX3_splash=${_BASE}/BMP/external3_splash_640x480.bmp
export _FW_splash=${_BASE}/BMP/ipfw_splash_640x480.bmp
export _FW2_splash=${_BASE}/BMP/ipfw2_splash_640x480.bmp
export _INT_splash=${_BASE}/BMP/internal_splash_640x480.bmp
export _V6_splash=${_BASE}/BMP/ipv6_splash_640x480.bmp

#
# Telnet ports
export _DNSHOST_telnetport=4453
export _EXTERNAL1_telnetport=4410
export _EXTERNAL2_telnetport=4420
export _EXTERNAL3_telnetport=4430
export _FIREWALL_telnetport=4450
export _FIREWALL2_telnetport=4250
export _INTERNAL_telnetport=44200
export _V6ONLY_telnetport=4460


# Bridge and Tap configurations.
#
# Note: em0 is used for the host interface.
#       Change as needed.
#
# Two bridge configuration
# Standard examples
#
#                        em0
#                         |
#  External1(tap1) -----bridge0------(tap0)Firewall
#  External2(tap2) -----+ |                  (tap4)
#  External3(tap3) -------+                    |
#                                            bridge1
#                                              |
#  Internal(tap5) -----------------------------+
#
#  sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 tap2 tap3 em0
#
#
#
# Two bridge configuration
# NAT & LSNAT examples
#
#
#
#                                    (firewall does LSNAT load balancing)
#  External1(tap1) -----bridge0------(tap0)Firewall
#  External2(tap2) -----+ |                  (tap4)
#  External3(tap3) -------+                    |
#  (these function as internal machines)     bridge1----em0
#                                              |
#  Internal(tap5) -----------------------------+
#  (this functions as an external machine)
#
#  sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 tap2 tap3  bridge1 tap4 tap5 em0
#
#
#
# Two bridge configuration
# NAT64/DNS64 example
#
#                       ipv4 only      NAT64 Translator
#  External1(tap1) ------bridge0-----(tap0)Firewall
#  (ipv4 only)             +                 (tap4)
#  (webserver)             |                   +
#                   dnshost(tap7)              |
#                    (DNS server)              |
#                    (running DNS64)           |
#                        (tap8)                |
#                          |                   |
#                          +                   |
#                     ipv6 only                |
#  v6only(tap6) --------bridge1----------------+
#  (v6 only host)
#
#  sudo /bin/sh mkbr.sh reset bridge0 tap0 tap1 tap7  bridge1 tap4 tap6 tap8
#
#
==========================================================



==========================================================


CODE: divert.c


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <sys/systm.h>

#define DIVERT_PORT 700

void hexdump(void *ptr, int length, const char *hdr, int flags);

int
main(int argc, char *argv[])
{
	int fd, s;
	struct sockaddr_in sin;
	socklen_t sin_len;


	printf("Opening divert on port %d\n",DIVERT_PORT);

	fd = socket(PF_DIVERT, SOCK_RAW, 0);
	if (fd == -1)
		err(1, "socket");

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(DIVERT_PORT);
	sin.sin_addr.s_addr = 0;

	sin_len = sizeof(struct sockaddr_in);

	s = bind(fd, (struct sockaddr *) &sin, sin_len);
	if (s == -1)
		err(1, "bind");

	for (;;) {
		ssize_t n;
		char packet[IP_MAXPACKET];
		struct ip *ip;
		struct tcphdr *th;
		int hlen;
		char src[64], dst[64], printbuff[12];


		memset(src, 0, sizeof(src));
		memset(dst, 0, sizeof(dst));
		memset(printbuff, 0, sizeof(printbuff));

		memset(packet, 0, sizeof(packet));
		n = recvfrom(fd, packet, sizeof(packet), 0,
		    (struct sockaddr *) &sin, &sin_len);
		if (n == -1) {
			warn("recvfrom");
			continue;
		}
		if (n < sizeof(struct ip)) {
			warnx("packet is too short");
			continue;
		}

		ip = (struct ip *) packet;
		hlen = ip->ip_hl << 2;
		if (hlen < sizeof(struct ip) || ntohs(ip->ip_len) < hlen ||
		    n < ntohs(ip->ip_len)) {
			warnx("invalid IPv4 packet");
			continue;
		}

		th = (struct tcphdr *) (packet + hlen);

		if (inet_ntop(AF_INET, &ip->ip_src, src,
		    sizeof(src)) == NULL)
			(void)strlcpy(src, "?", sizeof(src));

		if (inet_ntop(AF_INET, &ip->ip_dst, dst,
		    sizeof(dst)) == NULL)
			(void)strlcpy(dst, "?", sizeof(dst));

		printf("%s:%u -> %s:%u\n",
		    src,
		    ntohs(th->th_sport),
		    dst,
		    ntohs(th->th_dport)
		);


		/*
		*  dump the packet in hex and ascii with hexdump(3)
		*/

		hexdump((void *)packet, n, "|",0);

		n = sendto(fd, packet, n, 0, (struct sockaddr *) &sin,
		    sin_len);
		if (n == -1)
			warn("sendto");
	}

	return 0;
}