I've been having a great time using an Uubntu VM as my ZeroTier controller. I've installed ztncui which provides a nice web UI to manage my ZeroTier network. One unforseen challenge moving from ZeroTier's own controller to my own was that I would no longer have the flow rules engine and instead would need to use their rules syntax. This on it's own isn't that big of a deal, especially since one can simply create a dummy network on ZeroTier's site, configure their flow rules, and then simply copy the rules syntax output. The real challenge was how the rules are stored in a .json config file located within ZeroTier's files, and these are root protected.
To get around this, I've created a very simple bash script. Now, fair warning...this was my first time ever creating something in Bash! You have been warned! That said...it works pretty well! You simply point it to a rules file, point it to your network's .json file, and it will handle the rest.
#!/bin/bash
# Version 1.0.0
#------------------------------
# Variables
#------------------------------
#Path to controller configs (this should already be correct)
controllerConfigPath=/var/lib/zerotier-one/controller.d/network
#Name of config file (Change me!)
controllerConfigName=1234567890123456.json
#Path to rules file (Change me!)
rulesPath=/home/user/rules.json
#Create complete path to file
controllerConfig="$controllerConfigPath/$controllerConfigName"
#------------------------------
# Prerequisite checks
#------------------------------
#Check if running with sudo
if [[ $EUID -ne 0 ]]; then
echo "This script must be run with elevated priviledges."
exit 1
fi
# Check that jq is installed.
if ! command -v jq 2>&1 >/dev/null 2>&1; then
echo "$(tput setaf 9)[Uh oh!]$(tput sgr0) This script requires jq which is not installed. Please install it with $(tput setaf 11)apt-get install jq$(tput sgr0)."
exit 1
fi
# Check that tr is installed.
if ! command -v tr 2>&1 >/dev/null 2>&1; then
echo "$(tput setaf 9)[Uh oh!]$(tput sgr0) This script requires tr which is not installed. Not having this is odd and may be a sign of this script being shit. If in doubt, try $(tput setaf 11)apt-get install coreutils$(tput sgr0)."
exit 1
fi
#Check that controller config exists
if [ ! -f $controllerConfig ]; then
echo "The specified controller config file does not exist. It is currently set to..."
echo $controllerConfig
exit 1
fi
#Check that rules file exists
if [ ! -f $rulesPath ]; then
echo "The specified rules file does not exist. It is currently set to..."
echo $rulesPath
exit 1
fi
#------------------------------
# Write New Rules!
#------------------------------
#Put rules file into variable for jq
newRules=$(cat "$rulesPath")
#Create a timestamped backup of the existing controller file.
cp $controllerConfig "$controllerConfigPath/$(date +"%H:%M:%S-%m.%d.%Y")-$controllerConfigName"
#Insert new rules into config file.
jq ".rules = $newRules" "$controllerConfig" > "${controllerConfig}.tmp" && mv "${controllerConfig}.tmp" "$controllerConfig"
#Remove whitespace from file.
tr -d '[:space:]' < "$controllerConfig" > "${controllerConfig}.tmp" && mv "${controllerConfig}.tmp" "$controllerConfig"
#Restart the ZeroTier One service
echo "Restarting ZeroTier One service..."
systemctl restart zerotier-one.service
systemctl status zerotier-one.service
echo "Done! Printed status above."
The script is using jq
to parse the JSON and add it into ZeroTier's existing .json file for your network. The easiest way to make this file is to simply copy the rules from ZeroTier's website. Create a new network, write your flow rules, and then copy the JSON from the preview window on the right. Here's an example of what this would look like if you copied ZeroTier's default rules.
[
{
"etherType": 2048,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 2054,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"etherType": 34525,
"not": true,
"or": false,
"type": "MATCH_ETHERTYPE"
},
{
"type": "ACTION_DROP"
},
{
"type": "ACTION_ACCEPT"
}
]