Script for automatically configuring a SmartOS zone as a router. See writeup mentioned at the top of the script.
#!/bin/bash | |
# SEE WRITEUP AT https://davi.dyoung.tech/index.php/posts/configuring-smartos-as-a-router-with-ospf-and-dhcp | |
echo "This is the mega router installer script. Yay!" | |
# find out whether we're a one-nic router or a two-nic router | |
read -p "How many nics do we have? [1/2] " nicn | |
case $nicn in | |
1) | |
TWO_NICS=0 | |
;; | |
2) | |
TWO_NICS=1 | |
;; | |
*) | |
echo "c'mon, you have to answer this question" | |
exit 0 | |
;; | |
esac | |
# if we have two nics then that means we must route things to the other interface | |
# where does the other interface live? | |
if [ $TWO_NICS == 1 ] | |
then | |
read -p "Enter the IPv4 address of net1: " NET1_IPv4 | |
read -p "Enter the network number of net1: " NET1_IPv4_NETWORK | |
read -p "Enter the netmask *number* of net1, as /24 syntax: " NET1_IPv4_NETMASK | |
read -p "Enter the long form of this, e.g. 255.255.255.0: " NET1_IPv4_NETMASK_LONG | |
read -p "Enter the IPv6 address of net1: " NET1_IPv6 | |
read -p "Enter the IPv6 network number of net1 (assume /64): " NET1_IPv6_NETWORK | |
# net1 probably wants a dhcp server... | |
read -p "Enter DHCPv4 pool start address: " NET1_DHCP4_START | |
read -p "Enter DHCPv4 pool end address: " NET1_DHCP4_END | |
read -p "Enter DHCPv6 pool start address: " NET1_DHCPv6_START | |
read -p "Enter DHCPv6 pool end address: " NET1_DHCPv6_STOP | |
# oh yeah, a dns subdomain... | |
read -p "Enter the DNS subnet name (e.g. lan): " DNS_PREFIX | |
else | |
read -p "Enter the extra IPv4 network reachable from here (e.g. 10.0.0.0/12): " MAGIC_ROUTABLE_IPv4 | |
read -p "Enter the extra IPv6 network reachable from here (e.g. 2001::/16): " MAGIC_ROUTABLE_IPv6 | |
fi | |
echo "Fixing /root/.vimrc..." | |
( cat << EOF | |
colorscheme desert | |
set nocompatible " Must come first because it changes other options. | |
syntax enable " Turn on syntax highlighting. | |
filetype plugin on " Turn on file type detection. | |
set showcmd " Display incomplete commands. | |
set showmode " Display the mode you're in. | |
set backspace=indent,eol,start " Intuitive backspacing. | |
set hidden " Handle multiple buffers better. | |
set wildmenu " Enhanced command line completion. | |
set wildmode=list:longest " Complete files like a shell. | |
set incsearch " Highlight matches as you type. | |
set hlsearch " Highlight matches. | |
set wrap " Turn on line wrapping. | |
set modeline " Allow per file config | |
EOF | |
) > /root/.vimrc | |
echo "Fixing /root/.bashrc..." | |
( cat << "EOF" | |
if [ "$PS1" ]; then | |
shopt -s checkwinsize cdspell extglob histappend | |
alias ll='ls -lF' | |
alias ls='ls --color=auto' | |
HISTCONTROL=ignoreboth | |
HISTIGNORE="[bf]g:exit:quit" | |
PS1="[\u@\h \w]\\$ " | |
if [ -n "$SSH_CLIENT" ]; then | |
PROMPT_COMMAND='echo -ne "\033]0;${HOSTNAME%%\.*} \007" && history -a' | |
fi | |
fi | |
alias ls='ls -laph --color' | |
EOF | |
) > /root/.bashrc | |
echo "Running pkgin to fetch updates..." | |
pkgin update | |
pkgin upgrade | |
echo "Installing packages..." | |
pkgin install mtr quagga | |
if [ $TWO_NICS ==1 ] | |
then | |
pkgin install isc-dhcpd | |
fi | |
# Configuring Zebra | |
echo "Configuring Zebra..." | |
( cat << EOF | |
! | |
! Zebra configuration saved from vty | |
! 2018/01/05 02:05:18 | |
! | |
log syslog | |
! | |
interface lo0 | |
no link-detect | |
! | |
interface net0 | |
no link-detect | |
ipv6 nd suppress-ra | |
ipv6 nd ra-interval 10 | |
ipv6 nd prefix 2001:470:xxxx:2099::/64 | |
! | |
EOF | |
) > /opt/local/etc/zebra/zebra.conf | |
if [ $TWO_NICS == 0 ] | |
then | |
( cat << EOF | |
interface net1 | |
no link-detect | |
ip address ${NET1_IPv4}/${NET1_IPv4_NETMASK} | |
no ipv6 nd suppress-ra | |
ipv6 nd managed-config-flag | |
ipv6 address ${NET1_IPv6_NETWORK}/64 | |
ipv6 nd prefix ${NET1_IPv6_NETWORK}/64 | |
! | |
! | |
! | |
line vty | |
! | |
EOF | |
) >> /opt/local/etc/zebra/zebra.conf | |
fi | |
# Configuring OSPF | |
echo "Configuring OSPF..." | |
if [ $TWO_NICS == 0 ] | |
then | |
( cat << EOF | |
! | |
! Zebra configuration saved from vty | |
! 2018/01/05 02:05:18 | |
! | |
log syslog | |
! | |
interface lo0 | |
! | |
interface net0 | |
! | |
router ospf | |
redistribute connected | |
network 172.20.99.0/24 area 0.0.0.0 | |
network ${MAGIC_ROUTABLE_IPv4} area 0.0.0.0 | |
! | |
line vty | |
! | |
EOF | |
) > /opt/local/etc/zebra/ospfd.conf | |
else | |
( cat << EOF | |
! | |
! Zebra configuration saved from vty | |
! 2018/01/05 02:05:18 | |
! | |
log syslog | |
! | |
interface lo0 | |
! | |
interface net0 | |
! | |
interface net1 | |
! | |
router ospf | |
redistribute connected | |
passive-interface net1 | |
network 172.20.99.0/24 area 0.0.0.0 | |
network ${NET1_IPv4_NETWORK}/${NET1_IPv4_NETMASK} area 0.0.0.0 | |
! | |
line vty | |
! | |
EOF | |
) > /opt/local/etc/zebra/ospfd.conf | |
fi | |
# Configuring OSPF6 | |
echo "Configuring OSPF6..." | |
if [ $TWO_NICS == 0 ] | |
then | |
( cat << EOF | |
! | |
! Zebra configuration saved from vty | |
! 2018/01/06 23:43:18 | |
! | |
log syslog | |
! | |
interface net0 | |
! | |
debug ospf6 lsa unknown | |
! | |
router ospf6 | |
redistribute static | |
redistribute connected | |
redistribute kernel | |
area 0.0.0.0 range 2001:470:xxxx:2099::/64 | |
area 0.0.0.0 range ${MAGIC_ROUTABLE_IPv6}/64 | |
! | |
interface net0 area 0.0.0.0 | |
! | |
line vty | |
! | |
EOF | |
) > /opt/local/etc/zebra/ospf6d.conf | |
else | |
( cat << EOF | |
! | |
! Zebra configuration saved from vty | |
! 2018/01/06 23:43:18 | |
! | |
log syslog | |
! | |
interface net0 | |
! | |
interface net1 | |
! | |
debug ospf6 lsa unknown | |
! | |
router ospf6 | |
redistribute static | |
redistribute connected | |
redistribute kernel | |
area 0.0.0.0 range 2001:470:xxxx:2099::/64 | |
area 0.0.0.0 range ${${NET1_IPv6_NETWORK}/64 | |
! | |
interface net0 area 0.0.0.0 | |
! | |
line vty | |
! | |
EOF | |
) > /opt/local/etc/zebra/ospf6d.conf | |
fi | |
# Configuring routeadm | |
echo "Configuring routeadm..." | |
echo "Selecting OSPF routing services..." | |
routeadm -s routing-svcs="quagga:ospf quagga:ospf6" | |
echo "Enabling IPv{4,6} routing and forwarding..." | |
routeadm -e ipv4-forwarding -e ipv4-routing -e ipv6-routing -e ipv6-forwarding | |
echo "Updating routeadm..." | |
routeadm -u | |
# Configuring ndpd | |
if [ $TWO_NICS == 1 ] | |
then | |
echo "Configuring NDPd..." | |
( cat << EOF | |
if net1 AdvSendAdvertisements True | |
if net1 AdvManagedFlag True | |
if net1 StatelessAddrConfig True | |
prefix ${NET1_IPv6_NETWORK}/64 net1 | |
EOF | |
) > /etc/inet/ndpd.conf | |
fi | |
# Configuring isc-dhcpd | |
if [ $TWO_NICS == 1 ] | |
then | |
echo "Configuring ISC-DHCPd..." | |
echo "Creating /opt/local/etc/dhcp/dhcpd.conf" | |
( cat << EOF | |
# dhcpd.conf | |
# | |
# Sample configuration file for ISC dhcpd | |
# | |
# option definitions common to all supported networks... | |
option domain-name "${DNS_PREFIX}.dav1d.biz"; | |
option domain-search "example.com"; | |
option domain-name-servers 172.20.99.2, 9.9.9.9; | |
default-lease-time 600; | |
max-lease-time 7200; | |
# If this DHCP server is the official DHCP server for the local | |
# network, the authoritative directive should be uncommented. | |
authoritative; | |
# Use this to send dhcp log messages to a different log file (you also | |
# have to hack syslog.conf to complete the redirection). | |
log-facility local7; | |
subnet ${NET1_IPv4_NETMASK} netmask ${NET1_IPv4_NETMASK_LONG} { | |
range ${NET1_DHCP4_START} ${NET1_DHCP4_END}; | |
option routers ${NET1_IPv4}; | |
} | |
EOF | |
) > /opt/local/etc/dhcp/dhcpd.conf | |
# Configuring isc-dhcpd6 | |
if [ $TWO_NICS == 1 ] | |
then | |
echo "Configuring ISC-DHCPd6..." | |
# Make an SMF service | |
echo "Making an SMF service" | |
# Make an XML file for the manifest | |
( cat << EOF | |
<?xml version='1.0'?> | |
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> | |
<service_bundle type='manifest' name='export'> | |
<service name='pkgsrc/isc-dhcpd6' type='service' version='0'> | |
<create_default_instance enabled='true'/> | |
<single_instance/> | |
<dependency name='network' grouping='require_all' restart_on='error' type='service'> | |
<service_fmri value='svc:/milestone/network:default'/> | |
</dependency> | |
<dependency name='filesystem-local' grouping='require_all' restart_on='none' type='service'> | |
<service_fmri value='svc:/system/filesystem/local:default'/> | |
</dependency> | |
<dependency name='config-file' grouping='require_all' restart_on='refresh' type='path'> | |
<service_fmri value='file:///opt/local/etc/dhcp/dhcpd6.conf'/> | |
</dependency> | |
<method_context> | |
<method_credential group='root' user='root'/> | |
</method_context> | |
<exec_method name='start' type='method' exec='/opt/local/lib/svc/method/isc-dhcpd6 start' timeout_seconds='30'/> | |
<exec_method name='stop' type='method' exec='/opt/local/lib/svc/method/isc-dhcpd6 stop' timeout_seconds='30'/> | |
<exec_method name='refresh' type='method' exec='/opt/local/lib/svc/method/isc-dhcpd6 refresh' timeout_seconds='30'/> | |
<template> | |
<common_name> | |
<loctext xml:lang='C'>ISC DHCP6 Server</loctext> | |
</common_name> | |
</template> | |
</service> | |
</service_bundle> | |
EOF | |
) > /root/isc-dhcpd6.xml | |
# Do some dodgy heredoc stuff to get the manifest into svccfg | |
svccfg << EOF | |
import /root/isc-dhcpd6.conf | |
end | |
EOF | |
# phew, that felt a shade evil | |
# Make an init script | |
echo "Making an init script" | |
( cat << "EOF" | |
#!/sbin/sh | |
# | |
# $NetBSD: isc-dhcpd.sh,v 1.1 2014/03/12 14:29:31 jperkin Exp $ | |
# | |
# Init script for isc-dhcpd. | |
# | |
case "$1" in | |
start) | |
if [ ! -d /var/db/isc-dhcp ]; then | |
mkdir -p /var/db/isc-dhcp | |
touch /var/db/isc-dhcp/dhcpd6.leases | |
chmod 0640 /var/db/isc-dhcp/dhcpd6.leases | |
fi | |
mkdir -p /var/run/isc-dhcp | |
chmod 0770 /var/run/isc-dhcp | |
/opt/local/sbin/dhcpd -6 -cf /opt/local/etc/dhcp/dhcpd6.conf | |
;; | |
stop) | |
if [ -s /var/run/isc-dhcp/isc-dhcpd6.pid ]; then | |
kill `cat /var/run/isc-dhcp/isc-dhcpd6.pid` | |
fi | |
;; | |
refresh) | |
$0 stop | |
$0 start | |
;; | |
esac | |
EOF | |
) > /opt/local/lib/svc/method/isc_dhcpd6 | |
chmod +x /opt/local/lib/svc/method/isc_dhcpd6 | |
# Make a config file | |
echo "Creating config file" | |
( cat << EOF | |
# Sample configuration file for ISC dhcpd | |
# | |
# option definitions common to all supported networks... | |
option dhcp6.domain-search "example.com"; | |
option dhcp6.name-servers 2001:470:xxxx:2099::2; | |
default-lease-time 600; | |
max-lease-time 7200; | |
# If this DHCP server is the official DHCP server for the local | |
# network, the authoritative directive should be uncommented. | |
authoritative; | |
# Use this to send dhcp log messages to a different log file (you also | |
# have to hack syslog.conf to complete the redirection). | |
log-facility local7; | |
subnet6 ${NET1_IPv6_NETWORK}/64 { | |
range6 ${NET1_DHCPv6_START} ${NET1_DHCPv6_STOP}; | |
ddns-domainname "${DNS_PREFIX}.dav1d.biz."; | |
ddns-rev-domainname "ip6.arpa."; | |
} | |
EOF | |
) > /opt/local/etc/dhcp/dhcpd6.conf | |
# Make a leases directory | |
echo "Making a leases directory" | |
mkdir -p /var/db/isc-dhcpd | |
# Touch a leases file | |
touch /var/db/isc-dhcpd/{dhcpd.leases,dhcpd.leases~,dhcpd6.leases,dhcpd6.leases~} | |
fi | |
# Generating boilerplate ipf config | |
echo "Generating ipfilter config files..." | |
echo "Writing ipf.conf" | |
( cat << EOF | |
# | |
# ipf.conf | |
# | |
# IP Filter rules to be loaded during startup | |
# | |
# See ipf(4) manpage for more information on | |
# IP Filter rules syntax. | |
# allow loopback | |
pass in quick on lo0 all | |
pass out quick on lo0 all | |
# pass all on net0 | |
pass in quick on net0 all | |
pass out quick on net0 all | |
# allow ping | |
pass in quick on net0 proto icmp from any to any | |
pass out quick on net0 proto icmp from any to any | |
# allow multicast for OSPF | |
pass in quick on net0 proto ospf from 172.20.99.0/24 to 224.0.0.5 | |
pass in quick on net0 proto ospf from 172.20.99.0/24 to 224.0.0.6 | |
pass out quick on net0 proto ospf from 172.20.99.0/24 to 224.0.0.5 | |
pass out quick on net0 proto ospf from 172.20.99.0/24 to 224.0.0.6 | |
# allow routernet traffic to bounce off the router | |
pass in quick on net0 from 172.20.99.0/24 to 172.20.99.0/24 | |
pass out quick on net0 from 172.20.99.0/24 to 172.20.99.0/24 | |
# allow broadcast to come in | |
pass in quick on net0 proto udp from 172.20.99.0/24 to 255.255.255.255 | |
pass in quick on net0 proto udp from 172.20.99.0/24 to 172.20.99.255 | |
pass out quick on net0 proto udp from 172.20.99.0/24 to 172.20.99.255 | |
pass out quick on net0 proto udp from 172.20.99.0/24 to 255.255.255.255 | |
EOF | |
) > /etc/ipf/ipf.conf | |
if [ $TWO_NICS == 1 ] | |
then | |
( cat << EOF | |
# pass all on net1 | |
pass in quick on net1 all | |
pass out quick on net1 all | |
# allow ping | |
pass in quick on net1 proto icmp from any to any | |
pass out quick on net1 proto icmp from any to any | |
# allow internet acess | |
pass out quick on net1 from any to ${NET1_IPv4}/${NET1_IPv4_NETMASK} | |
pass in quick on net1 from ${NET1_IPv4}/${NET1_IPv4_NETMASK} to any | |
pass out quick on net1 from ${NET1_IPv4}/${NET1_IPv4_NETMASK} to any keep state | |
EOF | |
) >> /etc/ipf/ipf.conf | |
fi | |
echo "Writing ipf6.conf" | |
( cat << EOF | |
# | |
# ipf.conf | |
# | |
# IP Filter rules to be loaded during startup | |
# | |
# See ipf(4) manpage for more information on | |
# IP Filter rules syntax. | |
# allow loopback to work | |
pass in quick on lo0 all | |
pass out quick on lo0 all | |
# drop frags | |
block in log quick all with short | |
# default policy | |
block in log on net0 all | |
block out log on net0 all | |
# allow ospf multicast | |
pass in quick on net0 proto ospf from 2001:470:xxxx:2099::/64 to ff02::5 | |
pass in quick on net0 proto ospf from fe80::/10 to ff02::5 | |
pass out quick on net0 proto ospf from 2001:470:xxxx:2099::/64 to ff02::5 | |
pass out quick on net0 proto ospf from fe80::/10 to ff02::5 | |
# and apparently ospf unicast is a thing | |
pass in quick on net0 proto ospf from fe80::/10 to fe80::/10 | |
pass out quick on net0 proto ospf from fe80::/10 to fe80::/10 | |
# allow ipv6-icmp to work on net0 | |
pass in quick on net0 proto ipv6-icmp from any to fe80::/10 | |
pass in quick on net0 proto ipv6-icmp from any to 2001:470:xxxx:2099::/64 | |
pass out quick on net0 proto ipv6-icmp from fe80::/10 to any | |
pass out quick on net0 proto ipv6-icmp from 2001:470:xxxx:2099::/64 to any | |
pass out quick on net0 proto ipv6-icmp from 2001:470:xxxx:245a::/64 to any | |
# allow the multicast groups necessary for ipv6 to work | |
pass in quick on net0 from ff00::/8 to any | |
pass in quick on net0 from any to ff00::/8 | |
pass out quick on net0 from ff00::/8 to any | |
pass out quick on net0 from any to ff00::/8 | |
# pass the other fe80 stuff | |
pass in quick on net0 from fe80::/10 to fe80::/10 | |
pass out quick on net0 from fe80::/10 to fe80::/10 | |
EOF | |
) > /etc/ipf/ipf6.conf | |
if [ $TWO_NICS == 1 ] | |
then | |
( cat << EOF | |
block in log on net1 all | |
block out log on net1 all | |
# permit icmpv6 on net1 | |
pass in quick on net0 proto ipv6-icmp from any to ${NET1_IPv6_NETWORK}/64 | |
pass in quick on net1 proto ipv6-icmp from fe80::/10 to any | |
pass in quick on net1 proto ipv6-icmp from ${NET1_IPv6_NETWORK}/64 to any | |
pass out quick on net1 proto ipv6-icmp from any to fe80::/10 | |
pass out quick on net1 proto ipv6-icmp from any to ${NET1_IPv6_NETWORK}/64 | |
# allow multicast on net1 | |
pass in quick on net1 from ff00::/8 to any | |
pass in quick on net1 from any to ff00::/8 | |
pass out quick on net1 from ff00::/8 to any | |
pass out quick on net1 from any to ff00::/8 | |
# more link-local on net1 | |
pass in quick on net1 from fe80::/10 to fe80::/10 | |
pass out quick on net1 from fe80::/10 to fe80::/10 | |
# allow internet access | |
# allow internet access | |
pass in quick on net1 from ${NET1_IPv6_NETWORK}/64 to any | |
pass out quick on net1 from any to ${NET1_IPv6_NETWORK}/64 | |
pass out quick on net0 from ${NET1_IPv6_NETWORK}/64 to any keep state | |
EOF | |
) >> /etc/ipf/ipf6.conf | |
fi | |
# Enable services | |
for SERVICE in quagga:zebra quagga:ospf quagga:ospf6 isc-dhcpd isc-dhcpd6 ipfilter | |
do | |
echo "Enabling ${SERVICE}..." | |
svcadm enable $SERVICE | |
done | |
# Reboot? | |
read -p "All done, reboot now? [Y/n] " DO_REBOOT | |
if [[ $DO_REBOOT == 'y' || $DO_REBOOT == 'Y' ]] | |
then | |
reboot | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment