You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

420 lines
9.3 KiB

  1. #!/bin/sh /etc/rc.common
  2. # Copyright (C) 2012-2013 OpenWrt.org
  3. START=95
  4. EXTRA_COMMANDS="up down show_key generate_key"
  5. LIST_SEP="
  6. "
  7. TMP_FASTD=/tmp/fastd
  8. FASTD_COMMAND=/usr/bin/fastd
  9. section_enabled() {
  10. config_get_bool enabled "$1" 'enabled' 0
  11. [ $enabled -gt 0 ]
  12. }
  13. error() {
  14. echo "${initscript}:" "$@" 1>&2
  15. }
  16. get_key_instance() {
  17. local s="$1"
  18. config_get secret "$s" secret
  19. if [ "$secret" = 'generate' ]; then
  20. secret=`"$FASTD_COMMAND" --generate-key --machine-readable`
  21. uci -q set fastd."$s".secret="$secret" && uci -q commit fastd
  22. fi
  23. echo "$secret"
  24. }
  25. escape_string() {
  26. local t=${1//\\/\\\\}
  27. echo -n "\"${t//\"/\\\"}\""
  28. }
  29. guard_value() {
  30. local t=${1//[^-a-z0-9\[\].:]/}
  31. echo -n "$t"
  32. }
  33. guard_remote() {
  34. local t=${1//[^-a-zA-Z0-9\[\].:\"% ]/}
  35. local quotes=${t//[^\"]/}
  36. if [ "${#quotes}" = 0 -o "${#quotes}" = 2 ]; then
  37. echo -n "$t"
  38. fi
  39. }
  40. yes_no() {
  41. case "$1" in
  42. 0|no|off|false|disabled) echo -n no;;
  43. *) echo -n yes;;
  44. esac
  45. }
  46. config_string_config='include $(escape_string "$value");'
  47. config_string_config_peer='include peer $(escape_string "$value");'
  48. config_string_config_peer_dir='include peers from $(escape_string "$value");'
  49. config_string_bind='bind $(guard_value "$value");'
  50. config_string_method='method $(escape_string "$value");'
  51. config_string_syslog_level='log to syslog level $(guard_value "$value");'
  52. config_string_mode='mode $(guard_value "$value");'
  53. config_string_interface='interface $(escape_string "$value");'
  54. config_string_mtu='mtu $(guard_value "$value");'
  55. config_string_peer_limit='peer limit $(guard_value "$value");'
  56. config_string_user='user $(escape_string "$value");'
  57. config_string_group='group $(escape_string "$value");'
  58. config_string_pmtu='pmtu $(yes_no "$value");'
  59. config_string_forward='forward $(yes_no "$value");'
  60. config_string_hide_ip_addresses='hide ip addresses $(yes_no "$value");'
  61. config_string_hide_mac_addresses='hide mac addresses $(yes_no "$value");'
  62. config_string_secure_handshakes='secure handshakes $(yes_no "$value");'
  63. config_string_packet_mark='packet mark $(guard_value "$value");'
  64. config_string_peer='peer $(escape_string "$value") {'
  65. config_string_peer_group='peer group $(escape_string "$value") {'
  66. peer_string_key='key $(escape_string "$value");'
  67. peer_string_float='float $(yes_no "$value");'
  68. peer_string_remote='remote $(guard_remote "$value");'
  69. generate_option() {
  70. local __string=$(eval echo \"\$$2\")
  71. local value="$1";
  72. eval echo "\"$__string\""
  73. }
  74. append_option() {
  75. local v; local len; local s="$1"; local prefix="$2"; local p="$3"
  76. config_get len "$s" "${p}_LENGTH"
  77. if [ -z "$len" ]; then
  78. config_get v "$s" "$p"
  79. [ -n "$v" ] && generate_option "$v" "${prefix}_string_${p}"
  80. else
  81. config_list_foreach "$s" "$p" generate_option "${prefix}_string_${p}"
  82. fi
  83. }
  84. append_options() {
  85. local p; local s="$1"; local prefix="$2"; shift; shift
  86. for p in $*; do
  87. append_option "$s" "$prefix" "$p"
  88. done
  89. }
  90. generate_config_secret() {
  91. echo "secret $(escape_string "$1");"
  92. }
  93. generate_peer_config() {
  94. local peer="$1"
  95. # These options are deprecated
  96. config_get address "$peer" address
  97. config_get hostname "$peer" hostname
  98. config_get address_family "$peer" address_family
  99. config_get port "$peer" port
  100. if [ "$address" -o "$hostname" ]; then
  101. if [ -z "$port" ]; then
  102. error "peer $peer: address or hostname, but no port given"
  103. return 1
  104. fi
  105. if [ "$hostname" ]; then
  106. generate_option peer_string_remote "$address_family \"$hostname\" port $port"
  107. fi
  108. if [ "$address" ]; then
  109. generate_option peer_string_remote "$address port $port"
  110. fi
  111. fi
  112. append_options "$peer" peer \
  113. key float remote
  114. }
  115. generate_single_peer_config() {
  116. local peer="$1"; local net="$2"
  117. config_get peer_net "$peer" net
  118. config_get peer_group "$peer" group
  119. [ "$net" = "$peer_net" -a "$peer_group" = '' ] || return 0
  120. section_enabled "$peer" || return 0
  121. generate_option "$peer" config_string_peer
  122. generate_peer_config "$peer"
  123. echo '}'
  124. }
  125. create_peer_config() {
  126. local peer="$1"; local net="$2"; local group="$3"; local path="$4"
  127. config_get peer_net "$peer" net
  128. config_get peer_group "$peer" group
  129. [ "$group" = "$peer_group" ] || return 0
  130. if [ "$net" != "$peer_net" ]; then
  131. [ -z "$group" ] || error "warning: the peer group of peer '$peer' doesn't match its net, the peer will be ignored"
  132. return 0
  133. fi
  134. section_enabled "$peer" || return 0
  135. generate_peer_config "$peer" >"$path/$peer"
  136. }
  137. update_peer_group() {
  138. local net="$1"; local group_dir="$2"; local group="$3"; local update_only="$4"
  139. local path="$TMP_FASTD/fastd.$net/$group_dir"
  140. rm -rf "$path"
  141. mkdir -p "$path"
  142. config_foreach create_peer_config 'peer' "$net" "$group" "$path"
  143. if [ -z "$update_only" ]; then
  144. generate_option "$path" config_string_config_peer_dir
  145. fi
  146. config_foreach generate_peer_group_config 'peer_group' "$net" "$group_dir" "$update_only" "$group"
  147. }
  148. generate_peer_group_config() {
  149. local group="$1"; local net="$2"; local group_dir="$3%$group"; local update_only="$4"; local parent="$5"
  150. config_get group_net "$group" net
  151. config_get group_parent "$group" parent
  152. [ "$parent" = "$group_parent" ] || return 0
  153. if [ "$net" != "$peer_net" ]; then
  154. [ -z "$parent" ] || error "warning: the parent of peer group '$group' doesn't match its net, the peer group will be ignored"
  155. return 0
  156. fi
  157. section_enabled "$group" || return 0
  158. if [ -z "$update_only" ]; then
  159. generate_option "$group" config_string_peer_group
  160. append_options "$group" config \
  161. config config_peer config_peer_dir peer_limit
  162. fi
  163. update_peer_group "$net" "$group_dir" "$group" "$update_only"
  164. if [ -z "$update_only" ]; then
  165. echo '}'
  166. fi
  167. }
  168. update_peer_groups() {
  169. local net="$1"; local update_only="$2"
  170. update_peer_group "$net" 'peers' '' "$update_only"
  171. }
  172. generate_config() {
  173. local s="$1"
  174. generate_option 'info' config_string_syslog_level
  175. append_options "$s" config \
  176. config config_peer config_peer_dir bind method syslog_level mode interface mtu peer_limit \
  177. user group pmtu forward hide_ip_addresses hide_mac_addresses secure_handshakes packet_mark
  178. config_get mode "$s" mode
  179. if [ "$mode" = "tun" ]; then
  180. config_foreach generate_single_peer_config 'peer' "$s"
  181. else
  182. update_peer_groups "$s"
  183. fi
  184. }
  185. generate_key_instance() {
  186. local s="$1"
  187. config_get secret "$s" secret
  188. if [ -z "$secret" -o "$secret" = 'generate' ]; then
  189. secret=`fastd --generate-key --machine-readable`
  190. uci -q set fastd."$s".secret="$secret" && uci -q commit fastd
  191. fi
  192. generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable
  193. }
  194. show_key_instance() {
  195. local s="$1"
  196. local secret=`get_key_instance "$s"`
  197. if [ -z "$secret" ]; then
  198. error "$s: secret is not set"
  199. return 1
  200. fi
  201. generate_config_secret "$secret" | "$FASTD_COMMAND" --config - --show-key --machine-readable
  202. }
  203. start_instance() {
  204. local s="$1"
  205. section_enabled "$s" || return 1
  206. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  207. config_get interface "$s" interface
  208. if [ -z "$interface" ]; then
  209. error "$s: interface is not set"
  210. return 1
  211. fi
  212. if ifconfig "$interface" &>/dev/null; then
  213. error "$s: interface '$interface' is already in use"
  214. return 1
  215. fi
  216. config_get mode "$s" mode
  217. if [ -z "$mode" ]; then
  218. error "$s: mode is not set"
  219. return 1
  220. fi
  221. local secret=`get_key_instance "$s"`
  222. if [ -z "$secret" ]; then
  223. error "$s: secret is not set"
  224. return 1
  225. fi
  226. rm -f "$SERVICE_PID_FILE"
  227. touch "$SERVICE_PID_FILE"
  228. config_get user "$s" user
  229. if [ "$user" ]; then
  230. chown "$user" "$SERVICE_PID_FILE"
  231. fi
  232. (generate_config_secret "$secret"; generate_config "$s") | service_start "$FASTD_COMMAND" --config - --daemon --pid-file "$SERVICE_PID_FILE"
  233. if ! ifconfig "$interface" >/dev/null 2>&1; then
  234. error "$s: startup failed"
  235. return 1
  236. fi
  237. config_get up "$s" up
  238. [ -n "$up" ] && sh -c "$up" - "$interface"
  239. }
  240. stop_instance() {
  241. local s="$1"
  242. section_enabled "$s" || return 1
  243. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  244. config_get interface "$s" interface
  245. if [ -z "$interface" ]; then
  246. error "$s: interface is not set"
  247. return 1
  248. fi
  249. if ! ifconfig "$interface" &>/dev/null; then
  250. error "$s: interface '$interface' does not exist"
  251. return 1
  252. fi
  253. config_get down "$s" down
  254. [ -n "$down" ] && sh -c "$down" - "$interface"
  255. service_stop "$FASTD_COMMAND"
  256. rm -rf "$TMP_FASTD/fastd.$s"
  257. }
  258. reload_instance() {
  259. local s="$1"
  260. section_enabled "$s" || return 1
  261. config_get mode "$s" mode
  262. [ "$mode" = "tun" ] && return 1
  263. update_peer_groups "$s" true
  264. SERVICE_PID_FILE="/var/run/fastd.$s.pid"
  265. service_reload "$FASTD_COMMAND"
  266. }
  267. start() {
  268. config_load 'fastd'
  269. config_foreach start_instance 'fastd'
  270. }
  271. stop() {
  272. config_load 'fastd'
  273. config_foreach stop_instance 'fastd'
  274. }
  275. reload() {
  276. config_load 'fastd'
  277. config_foreach reload_instance 'fastd'
  278. }
  279. up() {
  280. local exists
  281. local instance
  282. config_load 'fastd'
  283. for instance in "$@"; do
  284. config_get exists "$instance" 'TYPE'
  285. if [ "$exists" = 'fastd' ]; then
  286. start_instance "$instance"
  287. fi
  288. done
  289. }
  290. down() {
  291. local exists
  292. local instance
  293. config_load 'fastd'
  294. for instance in "$@"; do
  295. config_get exists "$instance" 'TYPE'
  296. if [ "$exists" = 'fastd' ]; then
  297. stop_instance "$instance"
  298. fi
  299. done
  300. }
  301. show_key() {
  302. local exists
  303. local instance
  304. config_load 'fastd'
  305. for instance in "$@"; do
  306. config_get exists "$instance" 'TYPE'
  307. if [ "$exists" = 'fastd' ]; then
  308. show_key_instance "$instance"
  309. fi
  310. done
  311. }
  312. generate_key() {
  313. local exists
  314. local instance
  315. config_load 'fastd'
  316. for instance in "$@"; do
  317. config_get exists "$instance" 'TYPE'
  318. if [ "$exists" = 'fastd' ]; then
  319. generate_key_instance "$instance"
  320. fi
  321. done
  322. }