diff options
Diffstat (limited to 'doc/examples/openwrt/fastd.init')
-rw-r--r-- | doc/examples/openwrt/fastd.init | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/doc/examples/openwrt/fastd.init b/doc/examples/openwrt/fastd.init new file mode 100644 index 0000000..3a20922 --- /dev/null +++ b/doc/examples/openwrt/fastd.init @@ -0,0 +1,425 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2012-2013 OpenWrt.org + +START=95 + +SERVICE_USE_PID=1 + +EXTRA_COMMANDS="up down show_key generate_key" + +LIST_SEP=" +" +TMP_FASTD=/tmp/fastd +FASTD_COMMAND=/usr/bin/fastd + + +section_enabled() { + config_get_bool enabled "$1" 'enabled' 0 + [ $enabled -gt 0 ] +} + +error() { + echo "${initscript}:" "$@" 1>&2 +} + +get_key_instance() { + local s="$1" + + config_get secret "$s" secret + if [ "$secret" = 'generate' ]; then + secret=`"$FASTD_COMMAND" --generate-key --machine-readable` + uci -q set fastd."$s".secret="$secret" && uci -q commit fastd + fi + + echo "$secret" +} + + +escape_string() { + local t=${1//\\/\\\\} + echo -n "\"${t//\"/\\\"}\"" +} + +guard_value() { + local t=${1//[^-a-z0-9\[\].:]/} + echo -n "$t" +} + +guard_remote() { + local t=${1//[^-a-zA-Z0-9\[\].:\"% ]/} + local quotes=${t//[^\"]/} + if [ "${#quotes}" = 0 -o "${#quotes}" = 2 ]; then + echo -n "$t" + fi +} + +yes_no() { + case "$1" in + 0|no|off|false|disabled) echo -n no;; + *) echo -n yes;; + esac +} + +config_string_config='include $(escape_string "$value");' +config_string_config_peer='include peer $(escape_string "$value");' +config_string_config_peer_dir='include peers from $(escape_string "$value");' +config_string_bind='bind $(guard_value "$value");' +config_string_method='method $(escape_string "$value");' +config_string_syslog_level='log to syslog level $(guard_value "$value");' +config_string_mode='mode $(guard_value "$value");' +config_string_interface='interface $(escape_string "$value");' +config_string_mtu='mtu $(guard_value "$value");' +config_string_peer_limit='peer limit $(guard_value "$value");' +config_string_user='user $(escape_string "$value");' +config_string_group='group $(escape_string "$value");' +config_string_pmtu='pmtu $(yes_no "$value");' +config_string_forward='forward $(yes_no "$value");' +config_string_hide_ip_addresses='hide ip addresses $(yes_no "$value");' +config_string_hide_mac_addresses='hide mac addresses $(yes_no "$value");' +config_string_secure_handshakes='secure handshakes $(yes_no "$value");' +config_string_packet_mark='packet mark $(guard_value "$value");' + +config_string_peer='peer $(escape_string "$value") {' +config_string_peer_group='peer group $(escape_string "$value") {' + +peer_string_key='key $(escape_string "$value");' +peer_string_float='float $(yes_no "$value");' +peer_string_remote='remote $(guard_remote "$value");' + +generate_option() { + local __string=$(eval echo \"\$$2\") + local value="$1"; + eval echo "\"$__string\"" +} + +append_option() { + local v; local len; local s="$1"; local prefix="$2"; local p="$3" + + config_get len "$s" "${p}_LENGTH" + + if [ -z "$len" ]; then + config_get v "$s" "$p" + [ -n "$v" ] && generate_option "$v" "${prefix}_string_${p}" + else + config_list_foreach "$s" "$p" generate_option "${prefix}_string_${p}" + fi +} + +append_options() { + local p; local s="$1"; local prefix="$2"; shift; shift + for p in $*; do + append_option "$s" "$prefix" "$p" + done +} + + +generate_config_secret() { + echo "secret $(escape_string "$1");" +} + + +generate_peer_config() { + local peer="$1" + + # These options are deprecated + config_get address "$peer" address + config_get hostname "$peer" hostname + config_get address_family "$peer" address_family + config_get port "$peer" port + + if [ "$address" -o "$hostname" ]; then + if [ -z "$port" ]; then + error "peer $peer: address or hostname, but no port given" + return 1 + fi + + if [ "$hostname" ]; then + generate_option peer_string_remote "$address_family \"$hostname\" port $port" + fi + + if [ "$address" ]; then + generate_option peer_string_remote "$address port $port" + fi + fi + + append_options "$peer" peer \ + key float remote +} + +generate_single_peer_config() { + local peer="$1"; local net="$2" + + config_get peer_net "$peer" net + config_get peer_group "$peer" group + [ "$net" = "$peer_net" -a "$peer_group" = '' ] || return 0 + + section_enabled "$peer" || return 0 + + generate_option "$peer" config_string_peer + generate_peer_config "$peer" + echo '}' +} + +create_peer_config() { + local peer="$1"; local net="$2"; local group="$3"; local path="$4" + + config_get peer_net "$peer" net + config_get peer_group "$peer" group + [ "$group" = "$peer_group" ] || return 0 + + if [ "$net" != "$peer_net" ]; then + [ -z "$group" ] || error "warning: the peer group of peer '$peer' doesn't match its net, the peer will be ignored" + return 0 + fi + + section_enabled "$peer" || return 0 + + generate_peer_config "$peer" >"$path/$peer" +} + +update_peer_group() { + local net="$1"; local group_dir="$2"; local group="$3"; local update_only="$4" + local path="$TMP_FASTD/fastd.$net/$group_dir" + + rm -rf "$path" + mkdir -p "$path" + + config_foreach create_peer_config 'peer' "$net" "$group" "$path" + + if [ -z "$update_only" ]; then + generate_option "$path" config_string_config_peer_dir + fi + + config_foreach generate_peer_group_config 'peer_group' "$net" "$group_dir" "$update_only" "$group" +} + +generate_peer_group_config() { + local group="$1"; local net="$2"; local group_dir="$3%$group"; local update_only="$4"; local parent="$5" + + config_get group_net "$group" net + config_get group_parent "$group" parent + [ "$parent" = "$group_parent" ] || return 0 + + if [ "$net" != "$peer_net" ]; then + [ -z "$parent" ] || error "warning: the parent of peer group '$group' doesn't match its net, the peer group will be ignored" + return 0 + fi + + section_enabled "$group" || return 0 + + if [ -z "$update_only" ]; then + generate_option "$group" config_string_peer_group + append_options "$group" config \ + config config_peer config_peer_dir peer_limit + fi + + update_peer_group "$net" "$group_dir" "$group" "$update_only" + + if [ -z "$update_only" ]; then + echo '}' + fi +} + +update_peer_groups() { + local net="$1"; local update_only="$2" + + update_peer_group "$net" 'peers' '' "$update_only" +} + +generate_config() { + local s="$1" + + generate_option 'info' config_string_syslog_level + + append_options "$s" config \ + config config_peer config_peer_dir bind method syslog_level mode interface mtu peer_limit \ + user group pmtu forward hide_ip_addresses hide_mac_addresses secure_handshakes packet_mark + + config_get mode "$s" mode + + if [ "$mode" = "tun" ]; then + config_foreach generate_single_peer_config 'peer' "$s" + else + update_peer_groups "$s" + fi +} + + +generate_key_instance() { + local s="$1" + + config_get secret "$s" secret + if [ -z "$secret" -o "$secret" = 'generate' ]; then + secret=`fastd --generate-key --machine-readable` + uci -q set fastd."$s".secret="$secret" && uci -q commit fastd + fi + + generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable +} + +show_key_instance() { + local s="$1" + + local secret=`get_key_instance "$s"` + if [ -z "$secret" ]; then + error "$s: secret is not set" + return 1 + fi + + generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable +} + +start_instance() { + local s="$1" + + section_enabled "$s" || return 1 + + SERVICE_PID_FILE="/var/run/fastd.$s.pid" + + config_get interface "$s" interface + if [ -z "$interface" ]; then + error "$s: interface is not set" + return 1 + fi + + if ifconfig "$interface" &>/dev/null; then + error "$s: interface '$interface' is already in use" + return 1 + fi + + config_get mode "$s" mode + if [ -z "$mode" ]; then + error "$s: mode is not set" + return 1 + fi + + local secret=`get_key_instance "$s"` + if [ -z "$secret" ]; then + error "$s: secret is not set" + return 1 + fi + + rm -f "$SERVICE_PID_FILE" + touch "$SERVICE_PID_FILE" + + config_get user "$s" user + if [ "$user" ]; then + chown "$user" "$SERVICE_PID_FILE" + fi + + (generate_config_secret "$secret"; generate_config "$s") | service_start "$FASTD_COMMAND" --config - --daemon --pid-file "$SERVICE_PID_FILE" + + if ! ifconfig "$interface" >/dev/null 2>&1; then + error "$s: startup failed" + return 1 + fi + + config_get up "$s" up + [ -n "$up" ] && sh -c "$up" - "$interface" +} + +stop_instance() { + local s="$1" + + section_enabled "$s" || return 1 + + SERVICE_PID_FILE="/var/run/fastd.$s.pid" + + config_get interface "$s" interface + if [ -z "$interface" ]; then + error "$s: interface is not set" + return 1 + fi + + if ! ifconfig "$interface" &>/dev/null; then + error "$s: interface '$interface' does not exist" + return 1 + fi + + config_get down "$s" down + [ -n "$down" ] && sh -c "$down" - "$interface" + + service_stop "$FASTD_COMMAND" + + rm -rf "$TMP_FASTD/fastd.$s" +} + +reload_instance() { + local s="$1" + + section_enabled "$s" || return 1 + + config_get mode "$s" mode + [ "$mode" = "tun" ] && return 1 + + update_peer_groups "$s" true + + SERVICE_PID_FILE="/var/run/fastd.$s.pid" + service_reload "$FASTD_COMMAND" +} + +start() { + config_load 'fastd' + config_foreach start_instance 'fastd' + return 0 +} + +stop() { + config_load 'fastd' + config_foreach stop_instance 'fastd' + return 0 +} + +reload() { + config_load 'fastd' + config_foreach reload_instance 'fastd' + return 0 +} + +up() { + local exists + local instance + config_load 'fastd' + for instance in "$@"; do + config_get exists "$instance" 'TYPE' + if [ "$exists" = 'fastd' ]; then + start_instance "$instance" + fi + done +} + +down() { + local exists + local instance + config_load 'fastd' + for instance in "$@"; do + config_get exists "$instance" 'TYPE' + if [ "$exists" = 'fastd' ]; then + stop_instance "$instance" + fi + done +} + +show_key() { + local exists + local instance + config_load 'fastd' + for instance in "$@"; do + config_get exists "$instance" 'TYPE' + if [ "$exists" = 'fastd' ]; then + show_key_instance "$instance" + fi + done +} + +generate_key() { + local exists + local instance + config_load 'fastd' + for instance in "$@"; do + config_get exists "$instance" 'TYPE' + if [ "$exists" = 'fastd' ]; then + generate_key_instance "$instance" + fi + done +} |