Skip to content

Instantly share code, notes, and snippets.

@fakuivan
Created February 11, 2020 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fakuivan/b0a46dd8e176cde599515930dd610974 to your computer and use it in GitHub Desktop.
Save fakuivan/b0a46dd8e176cde599515930dd610974 to your computer and use it in GitHub Desktop.
jq based bash script used to configure zerotier's rule engine via the controller API
#!/usr/bin/env bash
run_on_ztncui () {
(source ~/containers/ztncui.sh && ztncui-compose exec -T ztncui bash -c "$1"); return $?
}
NETWORKS="$(run_on_ztncui 'curl -s -X GET --header "X-ZT1-Auth: $ZT_TOKEN" "$ZT_ADDR"/controller/network')"
for rules_file in ./rules/*.ztrules; do
nwid="$(python3 -c "import pathlib, sys; print(pathlib.Path(sys.argv[1]).stem)" "$rules_file")" &&
# Check if network id matches any network on the controller
{ [[ "$(echo "$NETWORKS" | jq --arg nwid "$nwid" 'any(. == $nwid)')" == "true" ]] || continue; } &&
config="$(run_on_ztncui 'curl -s -X GET --header "X-ZT1-Auth: $ZT_TOKEN" "$ZT_ADDR"/controller/network/'"$(printf %q "$nwid")")" &&
#npm install -g zerotier-rule-compiler
rules_compiled="$(node /usr/local/lib/node_modules/zerotier-rule-compiler/cli.js "$rules_file")" &&
config_merged="$(jq -s '.[1] * .[0].config' <(echo "$rules_compiled") <(echo "$config"))" &&
echo Writing final config
final_config="$(echo "$config_merged" | run_on_ztncui 'curl -s -X POST --header "X-ZT1-Auth: $ZT_TOKEN" -d @- "$ZT_ADDR"/controller/network/'"$(printf %q "$nwid")")" &&
# jd could be used instead
diff -u <(echo "$config" | jq .) <(echo "$final_config" | jq .) --color &&
rules_file="./rules/$nwid.caps.json"
if [[ -r "$rules_file" ]]; then
members="$(run_on_ztncui 'curl -s -X GET --header "X-ZT1-Auth: $ZT_TOKEN" "$ZT_ADDR"/controller/network/'"$(printf %q "$nwid")"'/member')"
caps="$(jq -s '.[0] as $members |
.[1].capabilitiesByName as $caps |
.[2] |
with_entries(select(.key | in($members))) |
with_entries(.value |= map(select(. | in($caps)) | $caps[.]))' \
<(echo "$members") <(echo "$rules_compiled") "$rules_file")"
i=0; while [[ "$i" < "$(echo "$caps" | jq 'keys | length')" ]]; do
member="$(echo "$caps" | jq -r --arg iter "$i" 'keys | .[$iter | tonumber]')"
member_config="$(run_on_ztncui 'curl -s -X GET --header "X-ZT1-Auth: $ZT_TOKEN" "$ZT_ADDR"/controller/network/'"$(printf %q "$nwid")"'/member/'"$(printf %q "$member")")"
member_caps="$(echo "$caps" | jq --arg member "$member" '.[$member]')"
member_config_merged="$(jq -s --arg member "$member" '.[0] * {"capabilities": .[1][$member]}' <(echo "$member_config") <(echo "$caps"))"
member_final_config="$(echo "$member_config_merged" |
run_on_ztncui 'curl -s -X POST --header "X-ZT1-Auth: $ZT_TOKEN" -d @- "$ZT_ADDR"/controller/network/'"$(printf %q "$nwid")"'/member/'"$(printf %q "$member")")"
diff -u <(echo "$member_config" | jq .) <(echo "$member_final_config" | jq .) --color
i=$(("$i" + 1))
done
fi
done
{
"feeeededdd": ["ipv6_router", "oofer"],
"deadbeefed": ["ipv6_router"]
}
#
# This is a default rule set that allows IPv4 and IPv6 traffic but otherwise
# behaves like a standard Ethernet switch.
#
# Please keep in mind that ZeroTier versions prior to 1.2.0 do NOT support advanced
# network rules.
#
# Since both senders and receivers enforce rules, you will get the following
# behavior in a network with both old and new versions:
#
# (old: 1.1.14 and older, new: 1.2.0 and newer)
#
# old <--> old: No rules are honored.
# old <--> new: Rules work but are only enforced by new side. Tags will NOT work, and
# capabilities will only work if assigned to the new side.
# new <--> new: Full rules engine support including tags and capabilities.
#
# We recommend upgrading all your devices to 1.2.0 as soon as convenient. Version
# 1.2.0 also includes a significantly improved software update mechanism that is
# turned on by default on Mac and Windows. (Linux and mobile are typically kept up
# to date using package/app management.)
#
# Allow ipv6 routers to make use of 6PLANE addressing
cap ipv6_router
id 100
accept
not chr ipauth
and not chr inbound
and ethertype ipv6
;
;
cap oofer
id 300
accept;
;
#
# Allow only IPv4, IPv4 ARP, and IPv6 Ethernet frames.
#
drop
not ethertype ipv4
and not ethertype arp
and not ethertype ipv6
;
#
# Uncomment to drop non-ZeroTier issued and managed IP addresses.
#
# This prevents IP spoofing but also blocks manual IP management at the OS level and
# bridging unless special rules to exempt certain hosts or traffic are added before
# this rule.
#
#drop
break
not chr ipauth
;
# Accept anything else. This is required since default is 'drop'.
accept;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment