ynh-hotspot 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. #!/bin/bash
  2. #
  3. # Wifi Hotspot app for YunoHost
  4. # Copyright (C) 2015 Julien Vaubourg <julien@vaubourg.com>
  5. # Contribute at https://github.com/labriqueinternet/hotspot_ynh
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. source /usr/share/yunohost/helpers
  20. # Functions
  21. ## State functions
  22. has_ip6delegatedprefix() {
  23. [[ -n "${ip6_net}" ]] && [[ "${ip6_net}" != "none" ]]
  24. }
  25. ip6addrfromdelegatedprefix() {
  26. echo "${ip6_net}1"
  27. }
  28. is_nat_set() {
  29. local gateway_interface=${1}
  30. iptables -w -nvt nat -L POSTROUTING | grep MASQUERADE | grep -q "${gateway_interface}"
  31. }
  32. is_ip4nataddr_set() {
  33. ip address show dev "${wifi_device}" 2>/dev/null | grep -q "${ip4_nat_prefix}.1/24"
  34. }
  35. is_ip6addr_set() {
  36. ip address show dev "${wifi_device}" 2>/dev/null | grep -q "$(ip6addrfromdelegatedprefix)/64"
  37. }
  38. is_ip6firewall_set() {
  39. ip6tables -w -nvL FORWARD | grep DROP | grep -q "${wifi_device}"
  40. }
  41. is_forwarding_set() {
  42. local ip6=$(sysctl net.ipv6.conf.all.forwarding | awk '{ print $NF; }')
  43. local ip4=$(sysctl net.ipv4.conf.all.forwarding | awk '{ print $NF; }')
  44. [[ "${ip6}" -eq 1 ]] && [[ "${ip4}" -eq 1 ]]
  45. }
  46. is_dhcpd6_running() {
  47. [[ -e "/run/dnsmasq/dnsmasq-dhcpdv6-ssid-${wifi_device}.pid" ]] && ps -p $(cat "/run/dnsmasq/dnsmasq-dhcpdv6-ssid-${wifi_device}.pid") > /dev/null
  48. }
  49. is_dhcpd4_running() {
  50. [[ -e "/run/dnsmasq/dnsmasq-dhcpdv4-ssid-${wifi_device}.pid" ]] && ps -p $(cat "/run/dnsmasq/dnsmasq-dhcpdv4-ssid-${wifi_device}.pid") > /dev/null
  51. }
  52. is_hostapd_running() {
  53. systemctl is-active hostapd &>/dev/null
  54. }
  55. is_running() {
  56. if has_ip6delegatedprefix; then
  57. if ! is_ip6addr_set; then
  58. return 1
  59. fi
  60. if [[ "${ip6_firewall}" -eq 1 ]] && ! is_ip6firewall_set; then
  61. return 1
  62. fi
  63. if ! is_dhcpd6_running; then
  64. return 1
  65. fi
  66. fi
  67. if ! is_ip4nataddr_set; then
  68. return 1
  69. fi
  70. if ! is_dhcpd4_running; then
  71. return 1
  72. fi
  73. if ! is_hostapd_running; then
  74. return 1
  75. fi
  76. if ! is_forwarding_set; then
  77. return 1
  78. fi
  79. if [[ -n ${new_gateway_interface} ]] && ! is_nat_set "${new_gateway_interface}"; then
  80. return 1
  81. fi
  82. return 0
  83. }
  84. ## Setters
  85. set_nat() {
  86. local gateway_interface=${1}
  87. iptables -w -t nat -A POSTROUTING -o "${gateway_interface}" -j MASQUERADE
  88. }
  89. set_ipaddr() {
  90. if ! is_ip4nataddr_set; then
  91. echo "hotspot ${wifi_device}: Set IPv4 NAT address"
  92. ip address add "${ip4_nat_prefix}.1/24" dev "${wifi_device}"
  93. fi
  94. if has_ip6delegatedprefix && ! is_ip6addr_set; then
  95. echo "hotspot ${wifi_device}: Set IPv6 address"
  96. ip address delete "$(ip6addrfromdelegatedprefix)/64" dev tun0 &>/dev/null
  97. ip address add "$(ip6addrfromdelegatedprefix)/64" dev "${wifi_device}"
  98. fi
  99. }
  100. set_ipfirewall() {
  101. # Set ipv6 firewalling
  102. if has_ip6delegatedprefix && [[ "${ip6_firewall}" -eq 1 ]] && ! is_ip6firewall_set; then
  103. echo "hotspot ${wifi_device}: Set IPv6 firewalling"
  104. ip6tables -w -A FORWARD -i "${wifi_device}" -j ACCEPT
  105. ip6tables -w -A FORWARD -o "${wifi_device}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  106. ip6tables -w -A FORWARD -o "${wifi_device}" -j DROP
  107. fi
  108. }
  109. set_forwarding() {
  110. sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null
  111. sysctl -w net.ipv4.conf.all.forwarding=1 >/dev/null
  112. }
  113. start_dhcpd() {
  114. # Run DHCPv4 server
  115. if ! is_dhcpd4_running; then
  116. echo "hotspot ${wifi_device}: Start the DHCPv4 server (dnsmasq)"
  117. dnsmasq -C /etc/dnsmasq.dhcpd/dhcpdv4-ssid-${wifi_device}.conf -p0 -x /run/dnsmasq/dnsmasq-dhcpv4-ssid-${wifi_device}.pid
  118. fi
  119. # Run DHCPv6 server
  120. if has_ip6delegatedprefix && ! is_dhcpd6_running; then
  121. echo "hotspot ${wifi_device}: Start the NDP and DHCPv6 server (dnsmasq)"
  122. dnsmasq -C /etc/dnsmasq.dhcpd/dhcpdv6-ssid-${wifi_device}.conf -p0 -x /run/dnsmasq/dnsmasq-dhcpv6-ssid-${wifi_device}.pid
  123. fi
  124. }
  125. configure_hostapd() {
  126. local ethaddr=$(ip link show dev "${wifi_device}" | grep link/ether | awk -F: '{ printf "02:%s:%s:%s:%s:00", $2, $3, $4, $5 }')
  127. ip link set addr "${ethaddr}" dev "${wifi_device}"
  128. }
  129. ## Unsetters
  130. unset_nat() {
  131. local gateway_interface=${1}
  132. iptables -w -t nat -D POSTROUTING -o "${gateway_interface}" -j MASQUERADE
  133. }
  134. unset_ipaddr() {
  135. if is_ip4nataddr_set; then
  136. echo "hotspot ${wifi_device}: Unset IPv4 NAT address"
  137. ip address delete "${ip4_nat_prefix}.1/24" dev "${wifi_device}"
  138. fi
  139. if has_ip6delegatedprefix && is_ip6addr_set; then
  140. echo "hotspot ${wifi_device}: Unset IPv6 address"
  141. ip address delete "$(ip6addrfromdelegatedprefix)/64" dev "${wifi_device}"
  142. fi
  143. }
  144. unset_ipfirewall() {
  145. if has_ip6delegatedprefix && [[ "${ip6_firewall}" -eq 1 ]] && is_ip6firewall_set; then
  146. echo "hotspot ${wifi_device}: Unset IPv6 firewalling"
  147. ip6tables -w -D FORWARD -i "${wifi_device}" -j ACCEPT
  148. ip6tables -w -D FORWARD -o "${wifi_device}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  149. ip6tables -w -D FORWARD -o "${wifi_device}" -j DROP
  150. fi
  151. }
  152. unset_forwarding() {
  153. sysctl -w net.ipv6.conf.all.forwarding=0 >/dev/null
  154. sysctl -w net.ipv4.conf.all.forwarding=0 >/dev/null
  155. }
  156. stop_dhcpd() {
  157. if is_dhcpd6_running; then
  158. echo "hotspot ${wifi_device}: Stop the NDP and DHCPv6 server (dnsmasq)"
  159. kill $(cat /run/dnsmasq/dnsmasq-dhcpdv6-ssid-${wifi_device}.pid)
  160. rm -f /run/dnsmasq/dnsmasq-dhcpdv6-ssid-${wifi_device}.pid
  161. fi
  162. if is_dhcpd4_running; then
  163. echo "hotspot ${wifi_device}: Stop the DHCPv4 server (dnsmasq)"
  164. kill $(cat /run/dnsmasq/dnsmasq-dhcpdv4-ssid-${wifi_device}.pid)
  165. rm -f /run/dnsmasq/dnsmasq-dhcpdv4-ssid-${wifi_device}.pid
  166. fi
  167. }
  168. stop_hostapd() {
  169. systemctl stop hostapd
  170. }
  171. if [ "$1" != restart ]; then
  172. # Variables
  173. echo -n "Retrieving Yunohost settings... "
  174. service_enabled=$(systemctl is-enabled ynh-hotspot)
  175. wifi_device=$(ynh_app_setting_get hotspot wifi_device)
  176. wifi_channel=$(ynh_app_setting_get hotspot wifi_channel)
  177. wifi_ssid=$(ynh_app_setting_get hotspot wifi_ssid)
  178. wifi_secure=$(ynh_app_setting_get hotspot wifi_secure)
  179. wifi_passphrase=$(ynh_app_setting_get hotspot wifi_passphrase)
  180. ip6_firewall=$(ynh_app_setting_get hotspot ip6_firewall)
  181. ip6_net=$(ynh_app_setting_get hotspot ip6_net)
  182. dns=$(ynh_app_setting_get hotspot dns)
  183. ip4_nat_prefix=$(ynh_app_setting_get hotspot ip4_nat_prefix)
  184. ip6_dns=""
  185. ip4_dns=""
  186. for ip in $(echo "${dns}" | tr ',' ' '); do
  187. if [[ "$ip" == *":"* ]]; then
  188. ip6_dns+="[$ip],"
  189. else
  190. ip4_dns+="$ip,"
  191. fi
  192. done
  193. # Remove trailing ,
  194. ip6_dns="${ip6_dns%%,}"
  195. ip4_dns="${ip4_dns%%,}"
  196. old_gateway_interface=$(ynh_app_setting_get hotspot gateway_interface)
  197. new_gateway_interface=$(ip route get 1.2.3.4 | awk '{ print $5; }')
  198. echo "OK"
  199. fi
  200. # Script
  201. case "$1" in
  202. start)
  203. if is_running; then
  204. echo "Already started"
  205. exit 0
  206. elif [[ "${service_enabled}" != "enabled" ]]; then
  207. echo "Not starting because hotspod service is disabled"
  208. exit 1
  209. fi
  210. if [[ -z "${wifi_device}" ]]; then
  211. echo "[FAIL] No wifi device selected. Make sure your wifi antenna is plugged-in / available and select it in the Hotspot admin"
  212. exit 1
  213. fi
  214. echo "[hotspot] Starting..."
  215. touch /tmp/.ynh-hotspot-started
  216. # Check old state of the ipv4 NAT settings
  217. if [[ -n "${old_gateway_interface}" ]] && [[ "${new_gateway_interface}" != "${old_gateway_interface}" ]] && is_nat_set "${old_gateway_interface}"; then
  218. unset_nat "${old_gateway_interface}"
  219. fi
  220. # Set ipv4 NAT
  221. if [[ -n "${new_gateway_interface}" ]] && ! is_nat_set "${new_gateway_interface}"; then
  222. echo "Set NAT"
  223. set_nat "${new_gateway_interface}"
  224. fi
  225. # Set forwarding for ipv6 and ipv4
  226. echo "Set forwarding"
  227. set_forwarding
  228. # Run hostapd
  229. if ! is_hostapd_running; then
  230. echo "Configuring hostapd"
  231. configure_hostapd
  232. echo "Starting hostapd..."
  233. if ! systemctl start hostapd; then
  234. journalctl -u hostapd -n 100 --no-hostname --no-pager
  235. exit 1
  236. fi
  237. sleep 1
  238. fi
  239. set_ipaddr
  240. set_ipfirewall
  241. start_dhcpd
  242. # Update dynamic settings
  243. ynh_app_setting_set hotspot gateway_interface "${new_gateway_interface}"
  244. ;;
  245. stop)
  246. echo "[hotspot] Stopping..."
  247. rm -f /tmp/.ynh-hotspot-started
  248. if [[ -n "${old_gateway_interface}" ]] && is_nat_set "${old_gateway_interface}"; then
  249. echo "Unset NAT"
  250. unset_nat "${old_gateway_interface}"
  251. fi
  252. echo "Unset forwarding"
  253. unset_forwarding
  254. unset_ipaddr
  255. unset_ipfirewall
  256. stop_dhcpd
  257. if is_hostapd_running; then
  258. echo "Stop hostapd"
  259. stop_hostapd
  260. fi
  261. ;;
  262. restart)
  263. $0 stop
  264. $0 start
  265. ;;
  266. status)
  267. exitcode=0
  268. if [[ "${service_enabled}" != "enabled" ]]; then
  269. echo "[FAIL] Hotspot Service disabled"
  270. exit 1
  271. fi
  272. if [[ -z "${wifi_device}" ]]; then
  273. echo "[FAIL] No wifi device selected. Make sure your wifi antenna is plugged-in / available and select it in the Hotspot admin"
  274. exit 1
  275. fi
  276. echo "[INFO] Autodetected internet interface: ${new_gateway_interface} (last start: ${old_gateway_interface})"
  277. if is_nat_set "${new_gateway_interface}"; then
  278. echo "[ OK ] IPv4 NAT set"
  279. else
  280. if [[ -z "${new_gateway_interface}" ]]; then
  281. echo "[INFO] No IPv4 NAT set (no internet interface)"
  282. else
  283. echo "[FAIL] No IPv4 NAT set"
  284. fi
  285. exitcode=1
  286. fi
  287. if is_forwarding_set; then
  288. echo "[ OK ] IPv6/IPv4 forwarding set"
  289. else
  290. echo "[FAIL] No IPv6/IPv4 forwarding set"
  291. exitcode=1
  292. fi
  293. if is_hostapd_running; then
  294. echo "[ OK ] Hostapd is running"
  295. else
  296. echo "[FAIL] Hostapd is not running"
  297. exitcode=1
  298. fi
  299. if has_ip6delegatedprefix; then
  300. echo "[INFO] hotspot ${wifi_device}: IPv6 delegated prefix found"
  301. echo "[INFO] hotspot ${wifi_device}: IPv6 address computed from the delegated prefix: $(ip6addrfromdelegatedprefix)"
  302. if is_ip6addr_set; then
  303. echo "[ OK ] hotspot ${wifi_device}: IPv6 address set"
  304. else
  305. echo "[FAIL] hotspot ${wifi_device}: No IPv6 address set"
  306. exitcode=1
  307. fi
  308. if is_ip6firewall_set; then
  309. echo "[ OK ] hotspot ${wifi_device}: IPv6 firewalling set"
  310. else
  311. if [[ "${ip6_firewall}" -eq 1 ]]; then
  312. echo "[FAIL] hotspot ${wifi_device}: No IPv6 firewalling set"
  313. else
  314. echo "[INFO] hotspot ${wifi_device}: No IPv6 firewalling set"
  315. fi
  316. exitcode=1
  317. fi
  318. if is_dhcpd6_running; then
  319. echo "[ OK ] hotspot ${wifi_device}: NDP and DHCPv6 server (dnsmasq) are running"
  320. else
  321. echo "[FAIL] hotspot ${wifi_device}: NDP and DHCPv6 server (dnsmasq) are not running"
  322. exitcode=1
  323. fi
  324. else
  325. echo "[INFO] hotspot ${wifi_device}: No IPv6 delegated prefix found"
  326. fi
  327. if is_dhcpd4_running; then
  328. echo "[ OK ] hotspot ${wifi_device}: DHCPv4 server (dnsmasq) is running"
  329. else
  330. echo "[FAIL] hotspot ${zifi_device}: DHCPv4 (dnsmasq) is not running"
  331. exitcode=1
  332. fi
  333. if is_ip4nataddr_set; then
  334. echo "[ OK ] hotspot ${wifi_device}: IPv4 NAT address set"
  335. else
  336. echo "[FAIL] hotspot ${wifi_device}: No IPv4 NAT address set"
  337. exitcode=1
  338. fi
  339. exit ${exitcode}
  340. ;;
  341. *)
  342. echo "Usage: $0 {start|stop|restart|status}"
  343. exit 1
  344. ;;
  345. esac
  346. exit 0