#!/bin/sh /etc/rc.common # # Copyright (C) 2010-2015 OpenWrt.org # Copyright (C) 2010 segal.di.ubi.pt # START=99 STOP=01 USE_PROCD=1 PROG=/usr/bin/ssh _log() { logger -p daemon.info -t sshtunnel "$@" } _err() { logger -p daemon.err -t sshtunnel "$@" } append_params() { local p v args for p in $*; do eval "v=\$$p" [ -n "$v" ] && args="$args -o $p=$v" done ARGS_options="${args# *}" } append_string() { local varname="$1"; local add="$2"; local separator="${3:- }"; local actual eval "actual=\$$varname" new="${actual:+$actual$separator}$add" eval "$varname=\$new" } validate_server_section() { uci_validate_section sshtunnel server "$1" \ 'user:string(1)' \ 'hostname:host' \ 'port:port' \ 'retrydelay:min(1):60' \ 'PKCS11Provider:file' \ 'CheckHostIP:or("yes", "no")' \ 'Compression:or("yes", "no")' \ 'CompressionLevel:range(1,9)' \ 'IdentityFile:file' \ 'LogLevel:or("QUIET", "FATAL", "ERROR", "INFO", "VERBOSE", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3"):INFO' \ 'ServerAliveCountMax:min(1)' \ 'ServerAliveInterval:min(1)' \ 'StrictHostKeyChecking:or("yes", "no")' \ 'TCPKeepAlive:or("yes", "no")' \ 'VerifyHostKeyDNS:or("yes", "no")' } validate_tunnelR_section() { uci_validate_section sshtunnel tunnelR "$1" \ 'remoteaddress:or(host, "*"):*' \ 'remoteport:port' \ 'localaddress:host' \ 'localport:port' } validate_tunnelL_section() { uci_validate_section sshtunnel tunnelL "$1" \ 'remoteaddress:host' \ 'remoteport:port' \ 'localaddress:or(host, "*"):*' \ 'localport:port' } validate_tunnelD_section() { uci_validate_section sshtunnel tunnelD "$1" \ 'localaddress:or(host, "*"):*' \ 'localport:port' } validate_tunnelW_section() { uci_validate_section sshtunnel tunnelW "$1" \ 'vpntype:or("ethernet", "point-to-point"):point-to-point' \ 'localdev:or("any", min(1))' \ 'remotedev:or("any", min(1))' } load_tunnelR() { config_get section_server "$1" "server" # continue to read next section if this is not for the current server [ "$server" = "$section_server" ] || return 0 # validate and load this remote tunnel config local remoteaddress remoteport localaddress localport validate_tunnelR_section "$1" || { _err "tunnelR ${1}: validation failed"; return 1; } [ -n "$remoteport" -a -n "$localport" -a -n "$remoteaddress" ] || { _err "tunnelR ${1}: missing required options"; return 1; } # count nr of valid sections to make sure there are at least one let count++ _log "tunnelR at ${server}: -R $remoteaddress:$remoteport:$localaddress:$localport" append_string "ARGS_tunnels" "-R $remoteaddress:$remoteport:$localaddress:$localport" } load_tunnelL() { config_get section_server "$1" "server" # continue to read next section if this is not for the current server [ "$server" = "$section_server" ] || return 0 # validate and load this remote tunnel config local remoteaddress remoteport localaddress localport validate_tunnelL_section "$1" || { _err "tunnelL ${1}: validation failed"; return 1; } [ -n "$remoteport" -a -n "$localport" -a -n "$remoteaddress" ] || { _err "tunnelL ${1}: missing required options"; return 1; } # count nr of valid sections to make sure there are at least one let count++ _log "tunnelL at ${server}: -L $localaddress:$localport:$remoteaddress:$remoteport" append_string "ARGS_tunnels" "-L $localaddress:$localport:$remoteaddress:$remoteport" } load_tunnelD() { config_get section_server "$1" "server" # continue to read next section if this is not for the current server [ "$server" = "$section_server" ] || return 0 # validate and load this remote tunnel config local localaddress localport validate_tunnelD_section "$1" || { _err "tunnelD ${1}: validation failed"; return 1; } [ -n "$localport" ] || { _err "tunnelD ${1}: missing localport"; return 1; } # count nr of valid sections to make sure there are at least one let count++ _log "proxy via ${server}: -D $localaddress:$localport" append_string "ARGS_tunnels" "-D $localaddress:$localport" } load_tunnelW() { config_get section_server "$1" "server" # continue to read next section if this is not for the current server [ "$server" = "$section_server" ] || return 0 # validate and load this remote tunnel config local localdev remotedev vpntype validate_tunnelW_section "$1" || { _err "tunnelW ${1}: validation failed"; return 1; } [ -n "$vpntype" -a -n "$localdev" -a -n "$remotedev" ] || { _err "tunnelW $1: missing or bad options"; return 1; } [ "$user" == "root" ] || { _err "tunnelW ${1}: root is required for tun"; return 1; } # count nr of valid sections to make sure there are at least one let count++ _log "tunnelW to ${server}: -w $localdev:$remotedev -o Tunnel=$vpntype" append_string "ARGS_tunnels" "-w $localdev:$remotedev -o Tunnel=$vpntype" } load_server() { server="$1" local user hostname port retrydelay PKCS11Provider CheckHostIP Compression \ CompressionLevel IdentityFile LogLevel ServerAliveCountMax \ ServerAliveInterval StrictHostKeyChecking TCPKeepAlive VerifyHostKeyDNS validate_server_section "$server" || { _err "server ${server}: validation failed"; return 1; } ARGS="" ARGS_options="" ARGS_tunnels="" count=0 config_foreach load_tunnelR "tunnelR" config_foreach load_tunnelL "tunnelL" config_foreach load_tunnelD "tunnelD" config_foreach load_tunnelW "tunnelW" [ "$count" -eq 0 ] && { _err "tunnels to ${server} not started - no tunnels defined"; return 1; } append_params CheckHostIP Compression CompressionLevel IdentityFile \ LogLevel PKCS11Provider ServerAliveCountMax ServerAliveInterval \ StrictHostKeyChecking TCPKeepAlive VerifyHostKeyDNS ARGS="$ARGS_options -o ExitOnForwardFailure=yes -o BatchMode=yes -nN $ARGS_tunnels -p $port $user@$hostname" procd_open_instance "$server" procd_set_param command "$PROG" $ARGS procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param respawn 0 "$retrydelay" 1 procd_close_instance } start_service() { config_load "sshtunnel" config_foreach load_server "server" } service_triggers() { procd_add_reload_trigger "sshtunnel" procd_open_validate validate_server_section validate_tunnelR_section validate_tunnelL_section validate_tunnelD_section validate_tunnelW_section procd_close_validate }