Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.