diff --git a/README.md b/README.md index f70b8eb..ee3b6d4 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in * Combine with the [VPN Client app](https://github.com/labriqueinternet/vpnclient_ynh) to obtain a VPN-protected WiFi -**Shipped version:** 2.0~ynh4 +**Shipped version:** 2.1~ynh1 ## Screenshots diff --git a/README_fr.md b/README_fr.md index 88c5f61..d19c85b 100644 --- a/README_fr.md +++ b/README_fr.md @@ -20,7 +20,7 @@ Si vous n’avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) po * À combiner avec l'[app VPN Client](https://github.com/labriqueinternet/vpnclient_ynh) pour obtenir un accès internet aumatiquement protégé par votre VPN -**Version incluse :** 2.0~ynh4 +**Version incluse :** 2.1~ynh1 ## Captures d’écran diff --git a/check_process b/check_process index aafd852..950622f 100644 --- a/check_process +++ b/check_process @@ -13,7 +13,7 @@ upgrade=1 upgrade=1 from_commit=539a1f26c30ba850455c63746d50ce3d8f33b119 backup_restore=1 - multi_instance=0 + multi_instance=1 change_url=0 ;;; Upgrade options ; commit=539a1f26c30ba850455c63746d50ce3d8f33b119 diff --git a/conf/dnsmasq.conf.tpl b/conf/dnsmasq.conf.tpl new file mode 100644 index 0000000..7af2560 --- /dev/null +++ b/conf/dnsmasq.conf.tpl @@ -0,0 +1,4 @@ +# Wifi Hotspot app for YunoHost + +# Enable DNS resolution on wifi interface +interface=__WIFI_DEVICE__ diff --git a/conf/hostapd.base.conf b/conf/hostapd.base.conf deleted file mode 100644 index 8ea3d7d..0000000 --- a/conf/hostapd.base.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface=__WIFI_DEVICE__ -hw_mode=g -__N_COMMENT__ieee80211n=1 -__N_COMMENT__wmm_enabled=1 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -channel=__WIFI_CHANNEL__ diff --git a/conf/hostapd.accesspoint.conf b/conf/hostapd.conf.tpl similarity index 63% rename from conf/hostapd.accesspoint.conf rename to conf/hostapd.conf.tpl index a726b1e..64e59eb 100644 --- a/conf/hostapd.accesspoint.conf +++ b/conf/hostapd.conf.tpl @@ -1,4 +1,9 @@ -__BSS_COMMENT__bss=__WIFI_INTERFACE__ +interface=__WIFI_DEVICE__ +hw_mode=g +macaddr_acl=0 +auth_algs=1 +ignore_broadcast_ssid=0 +channel=__WIFI_CHANNEL__ ssid=__WIFI_SSID__ __SEC_COMMENT__wpa=2 __SEC_COMMENT__wpa_passphrase=__WIFI_PASSPHRASE__ diff --git a/conf/openvpn_90-hotspot b/conf/openvpn_90-hotspot new file mode 100644 index 0000000..ce09c25 --- /dev/null +++ b/conf/openvpn_90-hotspot @@ -0,0 +1,3 @@ +#!/bin/bash + +systemctl restart __SERVICE_NAME__ \ No newline at end of file diff --git a/conf/systemd.service b/conf/systemd.service index 6268e69..1537aca 100644 --- a/conf/systemd.service +++ b/conf/systemd.service @@ -6,8 +6,8 @@ After=network.target [Service] Type=oneshot User=root -ExecStart=/usr/local/bin/ynh-hotspot start -ExecStop=/usr/local/bin/ynh-hotspot stop +ExecStart=/usr/local/bin/__SERVICE_NAME__ start +ExecStop=/usr/local/bin/__SERVICE_NAME__ stop RemainAfterExit=yes [Install] diff --git a/conf/systemd_hostapd.service b/conf/systemd_hostapd.service new file mode 100644 index 0000000..14ad3eb --- /dev/null +++ b/conf/systemd_hostapd.service @@ -0,0 +1,12 @@ +[Unit] +Description=LSB: Advanced IEEE 802.11 management daemon +After=remote-fs.target +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +Restart=no +TimeoutSec=5min +ExecStart=/usr/sbin/hostapd /etc/hostapd/__APP__/hostapd.conf +ExecReload=/bin/kill -HEP $MAINPID diff --git a/conf/ynh-hotspot b/conf/ynh-hotspot index 546d283..a98d557 100644 --- a/conf/ynh-hotspot +++ b/conf/ynh-hotspot @@ -17,88 +17,95 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +source /usr/share/yunohost/helpers + # Functions ## State functions -has_vpnclient_app() { - [ -e /tmp/.ynh-vpnclient-started ] -} - has_ip6delegatedprefix() { - local i=${1} - - [[ -n "${ip6_net[${i}]}" ]] && [[ "${ip6_net[${i}]}" != "none" ]] + [[ -n "${ip6_net}" ]] && [[ "${ip6_net}" != "none" ]] } ip6addrfromdelegatedprefix() { - local i=${1} - - echo "${ip6_net[${i}]}${i}001" + echo "${ip6_net}1" } is_nat_set() { local gateway_interface=${1} - iptables -w -nvt nat -L POSTROUTING | grep MASQUERADE | grep -q "${gateway_interface}" } is_ip4nataddr_set() { - local i=${1} - local dev=$(devfromid "${i}") - - ip address show dev "${dev}" 2>/dev/null | grep -q "${ip4_nat_prefix[${i}]}.1/24" + ip address show dev "${wifi_device}" 2>/dev/null | grep -q "${ip4_nat_prefix}.1/24" } is_ip6addr_set() { - local i=${1} - local dev=$(devfromid "${i}") - - ip address show dev "${dev}" 2>/dev/null | grep -q "$(ip6addrfromdelegatedprefix $i)/64" + ip address show dev "${wifi_device}" 2>/dev/null | grep -q "$(ip6addrfromdelegatedprefix)/64" } is_ip6firewall_set() { - local i=${1} - local dev=$(devfromid "${i}") - - ip6tables -w -nvL FORWARD | grep DROP | grep -q "${dev}" + ip6tables -w -nvL FORWARD | grep DROP | grep -q "${wifi_device}" } is_forwarding_set() { local ip6=$(sysctl net.ipv6.conf.all.forwarding | awk '{ print $NF; }') local ip4=$(sysctl net.ipv4.conf.all.forwarding | awk '{ print $NF; }') - [ "${ip6}" -eq 1 ] && [ "${ip4}" -eq 1 ] + [[ "${ip6}" -eq 1 ]] && [[ "${ip4}" -eq 1 ]] } is_dhcpd6_running() { - local i=${1} - - ps aux | grep "dhcpdv6-ssid${i}" | grep -qv grep + [[ -e "/run/dnsmasq/dnsmasq-dhcpdv6-$app.pid" ]] && ps -p $(cat "/run/dnsmasq/dnsmasq-dhcpdv6-$app.pid") > /dev/null } is_dhcpd4_running() { - local i=${1} - - ps aux | grep "dhcpdv4-ssid${i}" | grep -qv grep + [[ -e "/run/dnsmasq/dnsmasq-dhcpdv4-$app.pid" ]] && ps -p $(cat "/run/dnsmasq/dnsmasq-dhcpdv4-$app.pid") > /dev/null } is_hostapd_running() { - systemctl is-active hostapd &>/dev/null + systemctl is-active "hostapd@${app}" &>/dev/null +} + +is_other_hostapd_running() { + other_hostapd_services=$(systemctl list-units --state=running hostapd@*.service | grep -v "^hostapd@$app.service") + + [[ -n "${other_hostapd_service}" ]] } is_running() { - for i in $(seq 0 $((${multissid} - 1))); do - (has_ip6delegatedprefix ${i} && is_ip6addr_set ${i} \ - && ([ "${ip6_firewall[${i}]}" -eq 1 ] && is_ip6firewall_set ${i} || [ "${ip6_firewall[${i}]}" -eq 0 ]) \ - && is_dhcpd6_running ${i} || ! has_ip6delegatedprefix ${i}) \ - && is_ip4nataddr_set ${i} && is_dhcpd4_running ${i} - - if [ ! $? -eq 0 ]; then + if has_ip6delegatedprefix; then + if ! is_ip6addr_set; then return 1 fi - done + if [[ "${ip6_firewall}" -eq 1 ]] && ! is_ip6firewall_set; then + return 1 + fi + if ! is_dhcpd6_running; then + return 1 + fi + fi - is_hostapd_running && is_forwarding_set && ([ -z "${new_gateway_interface}" ] || is_nat_set "${new_gateway_interface}") + if ! is_ip4nataddr_set; then + return 1 + fi + + if ! is_dhcpd4_running; then + return 1 + fi + + if ! is_hostapd_running; then + return 1 + fi + + if ! is_forwarding_set; then + return 1 + fi + + if [[ -n ${new_gateway_interface} ]] && ! is_nat_set "${new_gateway_interface}"; then + return 1 + fi + + return 0 } ## Setters @@ -110,33 +117,26 @@ set_nat() { } set_ipaddr() { - local i=${1} - local dev=$(devfromid "${i}") - - if ! is_ip4nataddr_set ${i}; then - echo "hotspot${i}: Set IPv4 NAT address" - ip address add "${ip4_nat_prefix[${i}]}.1/24" dev "${dev}" + if ! is_ip4nataddr_set; then + echo "hotspot ${wifi_device}: Set IPv4 NAT address" + ip address add "${ip4_nat_prefix}.1/24" dev "${wifi_device}" fi - if has_ip6delegatedprefix ${i} && ! is_ip6addr_set ${i}; then - echo "hotspot${i}: Set IPv6 address" - ip address delete "$(ip6addrfromdelegatedprefix $i)/64" dev tun0 &>/dev/null - ip address add "$(ip6addrfromdelegatedprefix $i)/64" dev "${dev}" + if has_ip6delegatedprefix && ! is_ip6addr_set; then + echo "hotspot ${wifi_device}: Set IPv6 address" + ip address delete "$(ip6addrfromdelegatedprefix)/64" dev tun0 &>/dev/null + ip address add "$(ip6addrfromdelegatedprefix)/64" dev "${wifi_device}" fi } set_ipfirewall() { - local i=${1} - local dev=$(devfromid "${i}") - # Set ipv6 firewalling - if has_ip6delegatedprefix ${i} && [ "${ip6_firewall[${i}]}" -eq 1 ] && ! is_ip6firewall_set ${i}; then - echo "hotspot${i}: Set IPv6 firewalling" - ip6tables -w -A FORWARD -i "${dev}" -j ACCEPT - ip6tables -w -A FORWARD -o "${dev}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - ip6tables -w -A FORWARD -o "${dev}" -j DROP + if has_ip6delegatedprefix && [[ "${ip6_firewall}" -eq 1 ]] && ! is_ip6firewall_set; then + echo "hotspot ${wifi_device}: Set IPv6 firewalling" + ip6tables -w -A FORWARD -i "${wifi_device}" -j ACCEPT + ip6tables -w -A FORWARD -o "${wifi_device}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + ip6tables -w -A FORWARD -o "${wifi_device}" -j DROP fi - } set_forwarding() { @@ -145,62 +145,22 @@ set_forwarding() { } start_dhcpd() { - local i=${1} - local dev=$(devfromid "${i}") - # Run DHCPv4 server - if ! is_dhcpd4_running ${i}; then - echo "hotspot${i}: Start the DHCPv4 server (dnsmasq)" - - cp /etc/dnsmasq.dhcpd/dhcpdv4{.conf.tpl,-ssid${i}.conf} - - sed "s|__WIFI_DEVICE__|${dev}|g" -i /etc/dnsmasq.dhcpd/dhcpdv4-ssid${i}.conf - sed "s|__IP4_DNS__|${ip4_dns[${i}]}|g" -i /etc/dnsmasq.dhcpd/dhcpdv4-ssid${i}.conf - sed "s|__IP4_NAT_PREFIX__|${ip4_nat_prefix[${i}]}|g" -i /etc/dnsmasq.dhcpd/dhcpdv4-ssid${i}.conf - - dnsmasq -C /etc/dnsmasq.dhcpd/dhcpdv4-ssid${i}.conf -p0 + if ! is_dhcpd4_running; then + echo "hotspot ${wifi_device}: Start the DHCPv4 server (dnsmasq)" + dnsmasq -C /etc/dnsmasq.$app/dhcpdv4.conf -p0 -x /run/dnsmasq/dnsmasq-dhcpv4-$app.pid fi # Run DHCPv6 server - if has_ip6delegatedprefix ${i} && ! is_dhcpd6_running ${i}; then - echo "hotspot${i}: Start the NDP and DHCPv6 server (dnsmasq)" - - cp /etc/dnsmasq.dhcpd/dhcpdv6{.conf.tpl,-ssid${i}.conf} - - sed "s|__WIFI_DEVICE__|${dev}|g" -i /etc/dnsmasq.dhcpd/dhcpdv6-ssid${i}.conf - sed "s|__IP6_DNS__|${ip6_dns[${i}]}|g" -i /etc/dnsmasq.dhcpd/dhcpdv6-ssid${i}.conf - sed "s|__IP6_NET__|${ip6_net[${i}]}|g" -i /etc/dnsmasq.dhcpd/dhcpdv6-ssid${i}.conf - - dnsmasq -C /etc/dnsmasq.dhcpd/dhcpdv6-ssid${i}.conf -p0 + if has_ip6delegatedprefix && ! is_dhcpd6_running; then + echo "hotspot ${wifi_device}: Start the NDP and DHCPv6 server (dnsmasq)" + dnsmasq -C /etc/dnsmasq.$app/dhcpdv6.conf -p0 -x /run/dnsmasq/dnsmasq-dhcpv6-$app.pid fi } configure_hostapd() { - local ethaddr=$(ip link show dev "${wifi_device}" | grep link/ether | awk -F: '{ printf "02:%s:%s:%s:%s:00", $2, $3, $4, $5 }') ip link set addr "${ethaddr}" dev "${wifi_device}" - - cp /etc/hostapd/hostapd.base.conf /etc/hostapd/hostapd.conf - sed "s|__WIFI_DEVICE__|${wifi_device}|g" -i /etc/hostapd/hostapd.conf - sed "s|__WIFI_CHANNEL__|${wifi_channel}|g" -i /etc/hostapd/hostapd.conf - sed "s|__N_COMMENT__||g" -i /etc/hostapd/hostapd.conf - - for i in $(seq 0 $((${multissid} - 1))); do - - [ "${wifi_secure[${i}]}" -eq 1 ] && local sec_comment="" || local sec_comment="#" - [ "${i}" -eq 0 ] && local bss_comment="#" || local bss_comment="" - - cp /etc/hostapd/hostapd.accesspoint.conf /etc/hostapd/hostapd.conf.tmp - - sed "s|__WIFI_INTERFACE__|hotspot${i}|g" -i /etc/hostapd/hostapd.conf.tmp - sed "s|__WIFI_SSID__|${wifi_ssid[${i}]}|g" -i /etc/hostapd/hostapd.conf.tmp - sed "s|__WIFI_PASSPHRASE__|${wifi_passphrase[${i}]}|g" -i /etc/hostapd/hostapd.conf.tmp - sed "s|__SEC_COMMENT__|${sec_comment}|g" -i /etc/hostapd/hostapd.conf.tmp - sed "s|__BSS_COMMENT__|${bss_comment}|g" -i /etc/hostapd/hostapd.conf.tmp - - cat /etc/hostapd/hostapd.conf.tmp >>/etc/hostapd/hostapd.conf - rm /etc/hostapd/hostapd.conf.tmp - done } ## Unsetters @@ -212,29 +172,23 @@ unset_nat() { } unset_ipaddr() { - local i=${1} - local dev=$(devfromid "${i}") - - if is_ip4nataddr_set ${i}; then - echo "hotspot${i}: Unset IPv4 NAT address" - ip address delete "${ip4_nat_prefix[${i}]}.1/24" dev "${dev}" + if is_ip4nataddr_set; then + echo "hotspot ${wifi_device}: Unset IPv4 NAT address" + ip address delete "${ip4_nat_prefix}.1/24" dev "${wifi_device}" fi - if has_ip6delegatedprefix ${i} && is_ip6addr_set ${i}; then - echo "hotspot${i}: Unset IPv6 address" - ip address delete "$(ip6addrfromdelegatedprefix $i)/64" dev "${dev}" + if has_ip6delegatedprefix && is_ip6addr_set; then + echo "hotspot ${wifi_device}: Unset IPv6 address" + ip address delete "$(ip6addrfromdelegatedprefix)/64" dev "${wifi_device}" fi } unset_ipfirewall() { - local i=${1} - local dev=$(devfromid "${i}") - - if has_ip6delegatedprefix ${i} && [ "${ip6_firewall[${i}]}" -eq 1 ] && is_ip6firewall_set ${i}; then - echo "hotspot${i}: Unset IPv6 firewalling" - ip6tables -w -D FORWARD -i "${dev}" -j ACCEPT - ip6tables -w -D FORWARD -o "${dev}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - ip6tables -w -D FORWARD -o "${dev}" -j DROP + if has_ip6delegatedprefix && [[ "${ip6_firewall}" -eq 1 ]] && is_ip6firewall_set; then + echo "hotspot ${wifi_device}: Unset IPv6 firewalling" + ip6tables -w -D FORWARD -i "${wifi_device}" -j ACCEPT + ip6tables -w -D FORWARD -o "${wifi_device}" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + ip6tables -w -D FORWARD -o "${wifi_device}" -j DROP fi } @@ -244,77 +198,21 @@ unset_forwarding() { } stop_dhcpd() { - local i=${1} - - if is_dhcpd6_running ${i}; then - echo "hotspot${i}: Stop the NDP and DHCPv6 server (dnsmasq)" - kill $(ps aux | grep 'dhcpdv6-ssid' | grep -v grep | awk '{ print $2 }') - rm -f /etc/dnsmasq.d/dhcpdv6-ssid*.conf + if is_dhcpd6_running; then + echo "hotspot ${wifi_device}: Stop the NDP and DHCPv6 server (dnsmasq)" + kill $(cat /run/dnsmasq/dnsmasq-dhcpdv6-$app.pid) + rm -f /run/dnsmasq/dnsmasq-dhcpdv6-$app.pid fi - if is_dhcpd4_running ${i}; then - echo "hotspot${i}: Stop the DHCPv4 server (dnsmasq)" - kill $(ps aux | grep 'dhcpdv4-ssid' | grep -v grep | awk '{ print $2 }') - rm -f /etc/dnsmasq.d/dhcpdv4-ssid*.conf + if is_dhcpd4_running; then + echo "hotspot ${wifi_device}: Stop the DHCPv4 server (dnsmasq)" + kill $(cat /run/dnsmasq/dnsmasq-dhcpdv4-$app.pid) + rm -f /run/dnsmasq/dnsmasq-dhcpdv4-$app.pid fi } -stop_dhcpd4() { - : -} - stop_hostapd() { - systemctl stop hostapd -} - -## Tools - -ynh_setting_get() { - - APP="$1" KEY="$2" python3 - </dev/null - if [ "$?" -eq 0 ]; then - new_gateway_interface=tun0 - fi - echo "OK" fi @@ -369,27 +248,26 @@ start) if is_running; then echo "Already started" exit 0 - elif [ "${service_enabled}" != "enabled" ]; then - echo "Not starting because hotspod service is disabled" + elif [[ "${service_enabled}" -eq 0 ]]; then + echo "Not starting because hotspot service is disabled" exit 1 fi - if [ -z "${wifi_device}" ]; then + if [[ -z "${wifi_device}" ]]; then echo "[FAIL] No wifi device selected. Make sure your wifi antenna is plugged-in / available and select it in the Hotspot admin" exit 1 fi echo "[hotspot] Starting..." - touch /tmp/.ynh-hotspot-started + touch /tmp/.${service_name}-started # Check old state of the ipv4 NAT settings - if [ -n "${old_gateway_interface}" ] && [ "${new_gateway_interface}" != "${old_gateway_interface}" ] && is_nat_set "${old_gateway_interface}"; then - + if [[ -n "${old_gateway_interface}" ]] && [[ "${new_gateway_interface}" != "${old_gateway_interface}" ]] && is_nat_set "${old_gateway_interface}"; then unset_nat "${old_gateway_interface}" fi # Set ipv4 NAT - if [ -n "${new_gateway_interface}" ] && ! is_nat_set "${new_gateway_interface}"; then + if [[ -n "${new_gateway_interface}" ]] && ! is_nat_set "${new_gateway_interface}"; then echo "Set NAT" set_nat "${new_gateway_interface}" fi @@ -404,66 +282,43 @@ start) configure_hostapd echo "Starting hostapd..." - if ! systemctl start hostapd; then + if ! systemctl start "hostapd@${app}"; then journalctl -u hostapd -n 100 --no-hostname --no-pager exit 1 fi sleep 1 - - # On single SSID, the hotspot interface will be wlan0 (or similar) - # in multissid, we additionally want to make sure that at least hotspot1 started - if [ "${multissid}" -gt 1 ]; then - i=0 - while ! ip link show dev "hotspot1" &>/dev/null; do - sleep 1 - if [ ${i} -gt 20 ]; then - echo "Failed to see hotspot interface showing up in 'ip a'" - stop_hostapd - exit 1 - fi - i=$(($i + 1)) - done - fi fi - # For each registred ssid - for i in $(seq 0 $((${multissid} - 1))); do - set_ipaddr ${i} - set_ipfirewall ${i} - start_dhcpd ${i} - done + set_ipaddr + set_ipfirewall + start_dhcpd # Update dynamic settings - ynh_setting_set hotspot gateway_interface "${new_gateway_interface}" + ynh_app_setting_set hotspot gateway_interface "${new_gateway_interface}" ;; stop) echo "[hotspot] Stopping..." - rm -f /tmp/.ynh-hotspot-started + rm -f /tmp/.${service_name}-started - if [ -n "${old_gateway_interface}" ] && is_nat_set "${old_gateway_interface}"; then - echo "Unset NAT" - unset_nat "${old_gateway_interface}" + if ! is_other_hostapd_running; then + if [[ -n "${old_gateway_interface}" ]] && is_nat_set "${old_gateway_interface}"; then + echo "Unset NAT" + unset_nat "${old_gateway_interface}" + fi + + echo "Unset forwarding" + unset_forwarding fi - echo "Unset forwarding" - unset_forwarding - - for i in $(seq 0 $((${multissid} - 1))); do - unset_ipaddr ${i} - unset_ipfirewall ${i} - stop_dhcpd ${i} - done + unset_ipaddr + unset_ipfirewall + stop_dhcpd if is_hostapd_running; then echo "Stop hostapd" stop_hostapd fi - - # Fix configuration - if has_vpnclient_app; then - ynh-vpnclient start - fi ;; restart) $0 stop @@ -472,12 +327,12 @@ restart) status) exitcode=0 - if [ "${service_enabled}" != "enabled" ]; then + if [[ "${service_enabled}" -eq 0 ]]; then echo "[FAIL] Hotspot Service disabled" exit 1 fi - if [ -z "${wifi_device}" ]; then + if [[ -z "${wifi_device}" ]]; then echo "[FAIL] No wifi device selected. Make sure your wifi antenna is plugged-in / available and select it in the Hotspot admin" exit 1 fi @@ -487,7 +342,7 @@ status) if is_nat_set "${new_gateway_interface}"; then echo "[ OK ] IPv4 NAT set" else - if [ -z "${new_gateway_interface}" ]; then + if [[ -z "${new_gateway_interface}" ]]; then echo "[INFO] No IPv4 NAT set (no internet interface)" else echo "[FAIL] No IPv4 NAT set" @@ -509,53 +364,51 @@ status) exitcode=1 fi - for i in $(seq 0 $((${multissid} - 1))); do - if has_ip6delegatedprefix ${i}; then - echo "[INFO] hotspot${i}: IPv6 delegated prefix found" - echo "[INFO] hotspot${i}: IPv6 address computed from the delegated prefix: $(ip6addrfromdelegatedprefix $i)" + if has_ip6delegatedprefix; then + echo "[INFO] hotspot ${wifi_device}: IPv6 delegated prefix found" + echo "[INFO] hotspot ${wifi_device}: IPv6 address computed from the delegated prefix: $(ip6addrfromdelegatedprefix)" - if is_ip6addr_set ${i}; then - echo "[ OK ] hotspot${i}: IPv6 address set" - else - echo "[FAIL] hotspot${i}: No IPv6 address set" - exitcode=1 - fi - - if is_ip6firewall_set ${i}; then - echo "[ OK ] hotspot${i}: IPv6 firewalling set" - else - if [ "${ip6_firewall[${i}]}" -eq 1 ]; then - echo "[FAIL] hotspot${i}: No IPv6 firewalling set" - else - echo "[INFO] hotspot${i}: No IPv6 firewalling set" - fi - exitcode=1 - fi - - if is_dhcpd6_running ${i}; then - echo "[ OK ] hotspot${i}: NDP and DHCPv6 server (dnsmasq) are running" - else - echo "[FAIL] hotspot${i}: NDP and DHCPv6 server (dnsmasq) are not running" - exitcode=1 - fi + if is_ip6addr_set; then + echo "[ OK ] hotspot ${wifi_device}: IPv6 address set" else - echo "[INFO] hotspot${i}: No IPv6 delegated prefix found" - fi - - if is_dhcpd4_running ${i}; then - echo "[ OK ] hotspot${i}: DHCPv4 server (dnsmasq) is running" - else - echo "[FAIL] hotspot${i}: DHCPv4 (dnsmasq) is not running" + echo "[FAIL] hotspot ${wifi_device}: No IPv6 address set" exitcode=1 fi - if is_ip4nataddr_set ${i}; then - echo "[ OK ] hotspot${i}: IPv4 NAT address set" + if is_ip6firewall_set; then + echo "[ OK ] hotspot ${wifi_device}: IPv6 firewalling set" else - echo "[FAIL] hotspot${i}: No IPv4 NAT address set" + if [[ "${ip6_firewall}" -eq 1 ]]; then + echo "[FAIL] hotspot ${wifi_device}: No IPv6 firewalling set" + else + echo "[INFO] hotspot ${wifi_device}: No IPv6 firewalling set" + fi exitcode=1 fi - done + + if is_dhcpd6_running; then + echo "[ OK ] hotspot ${wifi_device}: NDP and DHCPv6 server (dnsmasq) are running" + else + echo "[FAIL] hotspot ${wifi_device}: NDP and DHCPv6 server (dnsmasq) are not running" + exitcode=1 + fi + else + echo "[INFO] hotspot ${wifi_device}: No IPv6 delegated prefix found" + fi + + if is_dhcpd4_running; then + echo "[ OK ] hotspot ${wifi_device}: DHCPv4 server (dnsmasq) is running" + else + echo "[FAIL] hotspot ${zifi_device}: DHCPv4 (dnsmasq) is not running" + exitcode=1 + fi + + if is_ip4nataddr_set; then + echo "[ OK ] hotspot ${wifi_device}: IPv4 NAT address set" + else + echo "[FAIL] hotspot ${wifi_device}: No IPv4 NAT address set" + exitcode=1 + fi exit ${exitcode} ;; diff --git a/config_panel.toml b/config_panel.toml index 7b11364..ff286d0 100644 --- a/config_panel.toml +++ b/config_panel.toml @@ -19,7 +19,7 @@ name = "Configuration" visible = "no_antenna" [main.service.status] - ask = "The status of your VPN is unknown." + ask = "The status of your Hotspot is unknown." type = "alert" style = "info" visible = "! no_antenna" @@ -52,194 +52,59 @@ name = "Configuration" visible = "! no_antenna" help = "Changing the channel may help with signal strength depending on neighbour WiFis" - [main.service.multissid] - ask = "Number of hotspots to broadcast" - type = "select" - choices.1 = "1" - choices.2 = "2" - choices.3 = "3" - visible = "! no_antenna" - - [main.hotspot1] - name = "Hotspot 1" + [main.hotspot] + name = "Hotspot" optional = false visible = "! no_antenna" - [main.hotspot1.wifi_ssid__1] + [main.hotspot.wifi_ssid] ask = "Name (SSID)" type = "string" - bind = "array_settings()" pattern.regexp = '^[\w \-]{1,32}$' pattern.error = "SSID in this app are limited to letter, number space, dash and underscores." - [main.hotspot1.wifi_secure__1] + [main.hotspot.wifi_secure] ask = "Secure" type = "boolean" - bind = "array_settings()" - [main.hotspot1.wifi_passphrase__1] + [main.hotspot.wifi_passphrase] ask = "Password (WPA2)" type = "string" - bind = "array_settings()" redact = true optional = true - visible = "wifi_secure__1" + visible = "wifi_secure" pattern.regexp = '^[a-zA-Z0-9]{8,63}$' pattern.error = "Only printable alphanumeric characters are permitted in your password. Maximal size 63 chars" - [main.hotspot1.advanced__1] + [main.hotspot.advanced] ask = "Advanced settings" type = "boolean" - bind = "array_settings()" - [main.hotspot1.ip4_nat_prefix__1] + [main.hotspot.ip4_nat_prefix] ask = "IPv4 NAT prefix (/24)" type = "string" - bind = "array_settings()" - visible = "advanced__1" + visible = "advanced" pattern.regexp = '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' pattern.error = "Please provide a private /24 range in the format xxx.xxx.xxx" - [main.hotspot1.ip6_net__1] + [main.hotspot.ip6_net] ask = "IPv6 delegated prefix" type = "string" - bind = "array_settings()" optional = true - visible = "advanced__1" + visible = "advanced" pattern.regexp = '^[0-9a-fA-F:]+$' pattern.error = "Please provide a valid IPv6 Prefix" - [main.hotspot1.ip6_firewall__1] + [main.hotspot.ip6_firewall] ask = "IPv6 firewall" type = "boolean" - bind = "array_settings()" - visible = "advanced__1" + visible = "advanced" - [main.hotspot1.dns__1] + [main.hotspot.dns] ask = "DNS resolvers" type = "tags" - bind = "array_settings()" - visible = "advanced__1" - pattern.regexp = '^([0-9.]{7,15}|[0-9a-fA-F:]+)$' - pattern.error = "Not an ip" - - [main.hotspot2] - name = "Hotspot 2" - visible = "! no_antenna && multissid >= 2" - - [main.hotspot2.wifi_ssid__2] - ask = "Name (SSID)" - type = "string" - bind = "array_settings()" - pattern.regexp = '^[\w \-]{1,32}$' - pattern.error = "SSID in this app are limited to letter, number space, dash and underscores." - - [main.hotspot2.wifi_secure__2] - ask = "Secure" - type = "boolean" - bind = "array_settings()" - - [main.hotspot2.wifi_passphrase__2] - ask = "Password (WPA2)" - type = "string" - bind = "array_settings()" - redact = true - visible = "wifi_secure__2" - pattern.regexp = '^[a-zA-Z0-9]{8,63}$' - pattern.error = "Only printable alphanumeric characters are permitted in your password. Maximal size 63 chars" - - [main.hotspot2.advanced__2] - ask = "Advanced settings" - type = "boolean" - bind = "array_settings()" - - [main.hotspot2.ip4_nat_prefix__2] - ask = "IPv4 NAT prefix (/24)" - type = "string" - bind = "array_settings()" - visible = "advanced__2" - pattern.regexp = '^[0-9.]{7,15}$' - pattern.error = "Please provide a valid IP" - - [main.hotspot2.ip6_net__2] - ask = "IPv6 delegated prefix" - type = "string" - bind = "array_settings()" - visible = "advanced__2" - pattern.regexp = '^[0-9a-fA-F:]+$' - pattern.error = "Please provide a valid IPv6 Prefix" - - [main.hotspot2.ip6_firewall__2] - ask = "IPv6 firewall" - type = "boolean" - bind = "array_settings()" - visible = "advanced__2" - - [main.hotspot2.dns__2] - ask = "DNS resolvers" - type = "tags" - bind = "array_settings()" - visible = "advanced__2" - pattern.regexp = '^([0-9.]{7,15}|[0-9a-fA-F:]+)$' - pattern.error = "Not an ip" - - [main.hotspot3] - name = "Hotspot 3" - visible = "! no_antenna && multissid >= 3" - - [main.hotspot3.wifi_ssid__3] - ask = "Name (SSID)" - type = "string" - bind = "array_settings()" - pattern.regexp = '^[\w \-]{1,32}$' - pattern.error = "SSID in this app are limited to letter, number space, dash and underscores." - - [main.hotspot3.wifi_secure__3] - ask = "Secure" - type = "boolean" - bind = "array_settings()" - - [main.hotspot3.wifi_passphrase__3] - ask = "Password (WPA2)" - type = "string" - bind = "array_settings()" - redact = true - visible = "wifi_secure__3" - pattern.regexp = '^[a-zA-Z0-9]{8,63}$' - pattern.error = "Only printable alphanumeric characters are permitted in your password. Maximal size 63 chars" - - [main.hotspot3.advanced__3] - ask = "Advanced settings" - type = "boolean" - bind = "array_settings()" - - [main.hotspot3.ip4_nat_prefix__3] - ask = "IPv4 NAT prefix (/24)" - type = "string" - bind = "array_settings()" - visible = "advanced__3" - pattern.regexp = '^[0-9.]{7,15}$' - pattern.error = "Please provide a valid IP" - - [main.hotspot3.ip6_net__3] - ask = "IPv6 delegated prefix" - type = "string" - bind = "array_settings()" - visible = "advanced__3" - pattern.regexp = '^[0-9a-fA-F:]+$' - pattern.error = "Please provide a valid IPv6 Prefix" - - [main.hotspot3.ip6_firewall__3] - ask = "IPv6 firewall" - type = "boolean" - bind = "array_settings()" - visible = "advanced__3" - - [main.hotspot3.dns__3] - ask = "DNS resolvers" - type = "tags" - bind = "array_settings()" - visible = "advanced__3" + bind = "null" + visible = "advanced" pattern.regexp = '^([0-9.]{7,15}|[0-9a-fA-F:]+)$' pattern.error = "Not an ip" diff --git a/manifest.json b/manifest.json index f2ecc47..8dff521 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "en": "Create and manager wifi networks, share Internet access and use YunoHost apps accross wifi", "fr": "Créer et configurer des réseaux wifi, partager l'accès a Internet et utiliser les applications YunoHost via wifi" }, - "version": "2.0~ynh4", + "version": "2.1~ynh1", "url": "https://github.com/labriqueinternet/hotspot_ynh", "license": "AGPL-3.0", "maintainer": { @@ -21,7 +21,7 @@ "requirements": { "yunohost": ">= 4.3.2" }, - "multi_instance": false, + "multi_instance": true, "services": [], "arguments": { "install" : [ diff --git a/scripts/_common.sh b/scripts/_common.sh index 0687a14..13ceb53 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -12,9 +12,33 @@ free_firmware_packages="firmware-ath9k-htc" # PERSONAL HELPERS #================================================= +function other_hotspot_apps() +{ + local app_shortname="${app%%__*}" + local hotspot_apps=$(yunohost app list --output-as json | jq -r .apps[].id | grep -F $app_shortname) + # Remove this app from hotspot apps list + grep -F -x -v $app <<< ${hotspot_apps} +} + function iw_devices() { - echo -n $(/sbin/iw dev | grep Interface | grep -v 'mon\.' | grep -v hotspot | awk '{ print $NF }') | tr ' ' '|' + /sbin/iw dev | grep Interface | grep -v 'mon\.' | grep -v hotspot | awk '{ print $NF }' +} + +function used_iw_devices() +{ + for hotspot_app in $(other_hotspot_apps); do + hotspot_wifi_device=$(ynh_app_setting_get --app=$hotspot_app --key=wifi_device) + if [[ -n "${hotspot_wifi_device}" ]]; then + echo "${hotspot_wifi_device}" + fi + done +} + +function unused_iw_devices() +{ + # Only prints devices that are not in the list of used devices + iw_devices | grep -F -v -f <(used_iw_devices) } function check_armbian_nonfree_conflict() @@ -48,6 +72,32 @@ function hot_reload_usb_wifi_cards() done } +function configure_hostapd() +{ + if [[ "${wifi_secure}" -eq 1 ]]; then + sec_comment="" + else + sec_comment="#" + fi + + ynh_add_config --template="/etc/hostapd/$app/hostapd.conf.tpl" --destination="/etc/hostapd/$app/hostapd.conf" +} + +function configure_dnsmasq() +{ + ynh_add_config --template="/etc/dnsmasq.$app/dnsmasq.conf.tpl" --destination="/etc/dnsmasq.d/$app.conf" + systemctl restart dnsmasq +} + +function configure_dhcp() +{ + ynh_add_config --template="/etc/dnsmasq.$app/dhcpdv4.conf.tpl" --destination="/etc/dnsmasq.$app/dhcpdv4.conf" + + if [[ -n "${ip6_net}" ]] && [[ "${ip6_net}" != "none" ]]; then + ynh_add_config --template="/etc/dnsmasq.$app/dhcpdv6.conf.tpl" --destination="/etc/dnsmasq.$app/dhcpdv6.conf" + fi +} + #================================================= # EXPERIMENTAL HELPERS #================================================= diff --git a/scripts/backup b/scripts/backup index 8284b04..de71cba 100644 --- a/scripts/backup +++ b/scripts/backup @@ -40,17 +40,22 @@ ynh_print_info --message="Declaring files to be backed up..." # BACKUP THE APP MAIN DIR #================================================= -for FILE in $(ls /etc/hostapd/hostapd.*.conf 2>/dev/null) -do - ynh_backup --src_path="$FILE" -done +ynh_backup --src_path="/etc/hostapd/$app/hostapd.conf.tpl" +ynh_backup --src_path="/etc/hostapd/$app/hostapd.conf" --not_mandatory -ynh_backup --src_path="/etc/dnsmasq.dhcpd/dhcpdv6.conf.tpl" -ynh_backup --src_path="/etc/dnsmasq.dhcpd/dhcpdv4.conf.tpl" +ynh_backup --src_path="/etc/dnsmasq.$app/dnsmasq.conf.tpl" +ynh_backup --src_path="/etc/dnsmasq.d/$app.conf" --not_mandatory + +ynh_backup --src_path="/etc/dnsmasq.$app/dhcpdv6.conf.tpl" +ynh_backup --src_path="/etc/dnsmasq.$app/dhcpdv6.conf" --not_mandatory + +ynh_backup --src_path="/etc/dnsmasq.$app/dhcpdv4.conf.tpl" +ynh_backup --src_path="/etc/dnsmasq.$app/dhcpdv4.conf" --not_mandatory ynh_backup --src_path="/usr/local/bin/$service_name" -ynh_backup --src_path="/etc/init.d/hostapd" +ynh_backup --src_path="/etc/openvpn/scripts/route-up.d/90-$service_name" +ynh_backup --src_path="/etc/openvpn/scripts/route-down.d/90-$service_name" #================================================= # SPECIFIC BACKUP @@ -59,6 +64,7 @@ ynh_backup --src_path="/etc/init.d/hostapd" #================================================= ynh_backup --src_path="/etc/systemd/system/$service_name.service" +ynh_backup --src_path="/etc/systemd/system/hostapd@$app.service" #================================================= # END OF SCRIPT diff --git a/scripts/config b/scripts/config index 78fa748..b493dbf 100644 --- a/scripts/config +++ b/scripts/config @@ -27,7 +27,7 @@ final_path=$(ynh_app_setting_get $app final_path) #================================================= get__no_antenna() { - if [[ $(iw_devices) == "" ]] + if [[ "$(unused_iw_devices)" == "" ]] then echo "value: true" else @@ -37,9 +37,9 @@ get__no_antenna() { get__status() { local service_enabled=$(ynh_app_setting_get $app service_enabled) - if systemctl is-active hostapd -q + if systemctl is-active hostapd@$app -q then - if [ $service_enabled -eq 1 ] + if [[ "$service_enabled" -eq 1 ]] then cat << EOF style: success @@ -54,7 +54,7 @@ ask: en: Your Hotspot is running, but it shouldn't ! EOF fi - elif [ $service_enabled -eq 1 ] + elif [[ "$service_enabled" -eq 1 ]] then cat << EOF style: danger @@ -62,7 +62,7 @@ ask: en: |- Your Hotspot is down ! Here are errors logged in the last 5 minutes \`\`\` -$(journalctl -u hostapd -n10 -o cat | sed 's/^/ /g') +$(journalctl -u hostapd@$app -n10 -o cat | sed 's/^/ /g') \`\`\` EOF else @@ -76,14 +76,15 @@ EOF } get__wifi_device() { - if [[ $(iw_devices) == "" ]] + local unused_wifi_devices=$(unused_iw_devices) + if [[ -z "${unused_wifi_devices}" ]] then echo "choices: []" else cat << EOF choices: EOF - for device in $(iw_devices | sed "s/|/ /g") + for device in $unused_wifi_devices do echo " $device: $device" done @@ -92,127 +93,112 @@ EOF echo "value: '$(ynh_app_setting_get $app wifi_device)'" } -get__array_settings() { - local short_setting="${1%%__*}" - local index="${1#*__}" - IFS='|' read -a values <<< "$(ynh_app_setting_get $app $short_setting)" - echo "value: \"${values[$(($index - 1))]:-}\"" +get__dns() { + ip6_net=$(ynh_app_setting_get --app=$app --key=ip6_net) + ip6_dns=$(ynh_app_setting_get --app=$app --key=ip6_dns | tr -d '[]') + ip4_nat_prefix=$(ynh_app_setting_get --app=$app --key=ip4_nat_prefix) + ip4_dns=$(ynh_app_setting_get --app=$app --key=ip4_dns) + + if [[ -n "${ip6_net}" ]] && [[ -z "${ip6_dns}" ]]; then + ip6_dns="${ip6_net}1" + fi + + if [[ -n "${ip4_nat_prefix}" ]] && [[ -z "${ip4_dns}" ]]; then + ip4_dns="${ip4_nat_prefix}.1" + fi + + echo "value: ${ip4_dns},${ip6_dns}" } #================================================= # SPECIFIC VALIDATORS FOR TOML SHORT KEYS #================================================= -is_unique() { - local short_setting="$1" - local short_setting__1="$1__1" - local short_setting__2="$1__2" - local short_setting__3="$1__3" - if [[ "${!short_setting__1}" == "${!short_setting__2}" ]] - then - return 1 - elif [ "$multissid" -ge "3" ] && [[ "${!short_setting__1}" == "${!short_setting__3}" ]] - then - return 1 - elif [ "$multissid" -ge "3" ] && [[ "${!short_setting__2}" == "${!short_setting__3}" ]] - then - return 1 - fi - return 0 -} + validate__wifi_ssid() { - local wifi_ssid_var="wifi_ssid__$1" - if [ "$multissid" -ge "$1" ] && [[ -z "${!wifi_ssid_var}" ]] + if [[ -z "${wifi_ssid}" ]] then echo 'SSID required' fi - if ! is_unique wifi_ssid - then - echo 'All Wifi names must be unique' - fi } validate__wifi_passphrase() { - local wifi_secure_var="wifi_secure__$1" - local wifi_passphrase_var="wifi_passphrase__$1" - if [ "$multissid" -ge "$1" ] && [[ "${!wifi_secure_var}" == "1" ]] && [[ -z "${!wifi_passphrase_var}" ]] + if [[ "${wifi_secure}" == "1" ]] && [[ -z "${wifi_passphrase}" ]] then echo 'In WPA2 secure mode, you need to provide a passphrase' fi } validate__ip4_nat_prefix() { - local ip4_nat_prefix_var="ip4_nat_prefix__$1" - if [ "$multissid" -ge "$1" ] && [[ -z "${!ip4_nat_prefix_var}" ]] + if [[ -z "${ip4_nat_prefix}" ]] then echo 'Private IPv4 nat prefix required' fi - if ! is_unique ip4_nat_prefix - then - echo 'All IPv4 prefix must be unique' - fi } validate__dns() { - local dns_var="dns__$1" - local ip6_net_var="dns__$1" - if [ "$multissid" -ge "$1" ] && ! echo "${!dns_var}" | grep -q "\." + if ! echo "${dns}" | grep -q "\." then echo 'IPv4 DNS required' fi - if [ "$multissid" -ge "$1" ] && [[ -n "${!ip6_net_var}" ]] && ! echo "${!dns_var}" | grep -q ":" + if [[ -n "${ip6_net}" ]] && ! echo "${dns}" | grep -q ":" then echo 'IPv6 DNS required' fi } -validate__array_settings() { - local short_setting="${1%%__*}" - local index="${1#*__}" - if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; - then - validate__$short_setting $index - fi -} - #================================================= # SPECIFIC SETTERS FOR TOML SHORT KEYS #================================================= -set__array_settings() { - local short_setting="${1%%__*}" - local index="${1#*__}" - local type="${types[$1]}" - local value="${!1}" - if [[ "$type" == "string" ]] && [ "$multissid" -lt "$index" ] - then - value="" - fi - local values="$(ynh_app_setting_get $app $short_setting | awk "BEGIN{FS=OFS=\"|\"} {\$${index}=\"${value}\"}"1)" - ynh_app_setting_set --app=$app --key=$short_setting --value="$values" - ynh_print_info --message="Configuration key '$short_setting' edited in app settings" -} +set__dns() { + ip6_dns="" + ip4_dns="" + for ip in $(echo "${dns}" | tr ',' ' '); do + if [[ "$ip" == *":"* ]]; then + ip6_dns+="[$ip]," + else + ip4_dns+="$ip," + fi + done + # Remove trailing , + ip6_dns="${ip6_dns%%,}" + ip4_dns="${ip4_dns%%,}" + + if [[ -n "${ip6_net}" ]] && [[ -z "${ip6_dns}" ]]; then + ip6_dns="${ip6_net}1" + fi + + if [[ -n "${ip4_nat_prefix}" ]] && [[ -z "${ip4_dns}" ]]; then + ip4_dns="${ip4_nat_prefix}.1" + fi + + ynh_app_setting_set $app ip6_dns "${ip6_dns}" + ynh_app_setting_set $app ip4_dns "${ip4_dns}" +} #================================================= # OVERWRITING VALIDATE STEP #================================================= -ynh_app_config_validate() { - _ynh_app_config_validate -} #================================================= # OVERWRITING APPLY STEP #================================================= ynh_app_config_apply() { - + service_name=$(ynh_app_setting_get --app=$app --key=service_name) + # Stop vpn client ynh_print_info --message="Stopping hotspot in order to edit files" - /usr/local/bin/ynh-hotspot stop + /usr/local/bin/${service_name} stop _ynh_app_config_apply - - # Start vpn client + + configure_hostapd + configure_dnsmasq + configure_dhcp + + # Start hotspot ynh_print_info --message="Starting hotspot service if needed" - /usr/local/bin/ynh-hotspot start + /usr/local/bin/${service_name} start } diff --git a/scripts/install b/scripts/install index 8032f2a..5f746d4 100644 --- a/scripts/install +++ b/scripts/install @@ -30,7 +30,7 @@ firmware_nonfree=$YNH_APP_ARG_FIRMWARE_NONFREE app=$YNH_APP_INSTANCE_NAME # the service name must match the service template files -service_name='ynh-hotspot' +service_name=ynh-$app #================================================= # CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS @@ -117,32 +117,32 @@ ynh_system_user_create --username=$app #================================================= ynh_script_progression --message="Configuring hotspot..." -if [[ ! -v ip6_net ]]; then # if ip6_net not set - ip6_net="" +ip6_net="" +ip6_dns="" - if [[ -e /tmp/.ynh-vpnclient-started ]]; then - vpnclient_ip6_net=$(ynh_app_setting_get vpnclient ip6_net 2>&1) - - if [[ $vpnclient_ip6_net =~ :: ]]; then - ip6_net=${vpnclient_ip6_net} - fi - fi +ip4_nat_prefix_index=${app##*__} +if [[ "${ip4_nat_prefix_index}" == "${app}" ]]; then + ip4_nat_prefix_index=0 fi +ip4_nat_prefix="10.${ip4_nat_prefix_index}.242" +ip4_dns="${ip4_nat_prefix}.1" hot_reload_usb_wifi_cards -wifi_device=$(iw_devices | awk -F\| '{ print $1 }') +wifi_device=$(unused_iw_devices | head -n 1) +wifi_secure=1 +wifi_channel=6 -ynh_app_setting_set --app=$app --key=multissid --value=1 -ynh_app_setting_set --app=$app --key=ssid_nb --value=1 ynh_app_setting_set --app=$app --key=wifi_ssid --value="${wifi_ssid}" -ynh_app_setting_set --app=$app --key=wifi_secure --value=1 +ynh_app_setting_set --app=$app --key=wifi_secure --value="${wifi_secure}" ynh_app_setting_set --app=$app --key=wifi_passphrase --value="${wifi_passphrase}" ynh_app_setting_set --app=$app --key=wifi_device --value="${wifi_device}" -ynh_app_setting_set --app=$app --key=wifi_channel --value=6 +ynh_app_setting_set --app=$app --key=wifi_channel --value="${wifi_channel}" +ynh_app_setting_set --app=$app --key=advanced --value=0 ynh_app_setting_set --app=$app --key=ip6_firewall --value=1 ynh_app_setting_set --app=$app --key=ip6_net --value="${ip6_net}" -ynh_app_setting_set --app=$app --key=dns --value="10.0.242.1" -ynh_app_setting_set --app=$app --key=ip4_nat_prefix --value=10.0.242 +ynh_app_setting_set --app=$app --key=ip6_dns --value="${ip6_dns}" +ynh_app_setting_set --app=$app --key=ip4_dns --value="${ip4_dns}" +ynh_app_setting_set --app=$app --key=ip4_nat_prefix --value="${ip4_nat_prefix}" if [[ -z $wifi_device ]]; then ynh_app_setting_set --app=$app --key=service_enabled --value=0 @@ -155,30 +155,35 @@ fi #================================================= ynh_script_progression --message="Copying configuration files..." -mkdir -pm 0755 /etc/dnsmasq.dhcpd/ -chown root: /etc/dnsmasq.dhcpd/ +mkdir -pm 0755 /etc/hostapd/$app/ +chown root: /etc/hostapd/$app/ -install -b -o root -g root -m 0644 ../conf/hostapd.*.conf /etc/hostapd/ -install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv6.conf.tpl /etc/dnsmasq.dhcpd/dhcpdv6.conf.tpl -install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv4.conf.tpl /etc/dnsmasq.dhcpd/dhcpdv4.conf.tpl +mkdir -pm 0755 /etc/dnsmasq.$app/ +chown root: /etc/dnsmasq.$app/ + +install -b -o root -g root -m 0644 ../conf/hostapd.conf.tpl /etc/hostapd/$app/hostapd.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq.conf.tpl /etc/dnsmasq.$app/dnsmasq.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv6.conf.tpl /etc/dnsmasq.$app/dhcpdv6.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv4.conf.tpl /etc/dnsmasq.$app/dhcpdv4.conf.tpl # Copy init script -install -o root -g root -m 0755 ../conf/$service_name /usr/local/bin/ +ynh_add_config --template="../conf/ynh-hotspot" --destination="/usr/local/bin/$service_name" +chmod 0755 "/usr/local/bin/$service_name" + +# Copy openvpn scripts +mkdir -pm 0755 /etc/openvpn/scripts +mkdir -pm 0755 /etc/openvpn/scripts/route-up.d +mkdir -pm 0755 /etc/openvpn/scripts/route-down.d +ynh_add_config --template="../conf/openvpn_90-hotspot" --destination="/etc/openvpn/scripts/route-up.d/90-$service_name" +ynh_add_config --template="../conf/openvpn_90-hotspot" --destination="/etc/openvpn/scripts/route-down.d/90-$service_name" +chmod 0755 "/etc/openvpn/scripts/route-up.d/90-${service_name}" +chmod 0755 "/etc/openvpn/scripts/route-down.d/90-${service_name}" #================================================= # CONFIGURE HOSTAPD #================================================= ynh_script_progression --message="Configuring hostapd..." -## hostapd -ynh_replace_string --match_string="^DAEMON_CONF=$" --replace_string="&/etc/hostapd/hostapd.conf" --target_file=/etc/init.d/hostapd -ynh_store_file_checksum --file="/etc/init.d/hostapd" - -# We also need to put this in /etc/default/hostapd because on some setup -# like RPi, the version of hostapd is different and /etc/init.d/hostapd -# isnt used ... instead the service is "pure systemd" ... -echo "DAEMON_CONF=/etc/hostapd/hostapd.conf" > /etc/default/hostapd - # Set default inits # The boot order of these services are important, so they are disabled by default # and the ynh-hotspot service handles them. @@ -186,6 +191,12 @@ systemctl disable hostapd --quiet 2>&1 systemctl stop hostapd 2>&1 systemctl unmask hostapd 2>&1 # On some system e.g. RPi, for some reason hostapd is masked after install ... +if [[ -n "${wifi_device}" ]]; then + configure_hostapd + configure_dnsmasq + configure_dhcp +fi + #================================================= # SETUP SYSTEMD #================================================= @@ -193,13 +204,15 @@ ynh_script_progression --message="Configuring a systemd service..." # Create a dedicated systemd config ynh_add_systemd_config --service=$service_name +# Create custom systemd config for hostapd to handle multiple wifi devices +ynh_add_systemd_config --service="hostapd@$app" --template="../conf/systemd_hostapd.service" #================================================= # INTEGRATE SERVICE IN YUNOHOST #================================================= ynh_script_progression --message="Integrating service in YunoHost..." -yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd" +yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd@$app" #================================================= # START SYSTEMD SERVICE diff --git a/scripts/remove b/scripts/remove index 4ccfd27..7b3d158 100644 --- a/scripts/remove +++ b/scripts/remove @@ -26,12 +26,9 @@ service_name=$(ynh_app_setting_get --app=$app --key=service_name) #================================================= # Remove the service from the list of services known by Yunohost (added from `yunohost service add`) -if yunohost service status $service_name >/dev/null 2>&1 -then - ynh_script_progression --message="Removing $app service" - yunohost service stop $service_name - yunohost service remove $service_name -fi +ynh_script_progression --message="Removing $app service" +yunohost service stop $service_name +yunohost service remove $service_name #================================================= # STOP AND REMOVE SERVICE @@ -40,6 +37,7 @@ ynh_script_progression --message="Stopping and removing the systemd service..." # Remove the dedicated systemd config ynh_remove_systemd_config --service=$service_name +ynh_remove_systemd_config --service="hostapd@$app" #================================================= # REMOVE DEPENDENCIES @@ -54,37 +52,37 @@ ynh_remove_app_dependencies #================================================= ynh_script_progression --message="Removing app main directory..." +ynh_secure_remove --file="/etc/openvpn/scripts/route-up.d/90-${service_name}" +ynh_secure_remove --file="/etc/openvpn/scripts/route-down.d/90-${service_name}" + # Remove the app directory securely ynh_secure_remove --file="/usr/local/bin/$service_name" -for FILE in $(ls /tmp/.ynh-hotspot-* 2>/dev/null) -do +for FILE in $(ls /tmp/.${service_name}-* 2>/dev/null); do ynh_secure_remove --file="$FILE" done # Remove confs -ynh_secure_remove --file="/etc/dnsmasq.dhcpd/dhcpdv6.conf.tpl" -ynh_secure_remove --file="/etc/dnsmasq.dhcpd/dhcpdv4.conf.tpl" -for FILE in $(ls /etc/hostapd/hostapd.*.conf 2>/dev/null) -do - ynh_secure_remove --file="$FILE" -done +ynh_secure_remove --file="/etc/dnsmasq.d/$app.conf" +systemctl restart dnsmasq + +ynh_secure_remove --file="/etc/dnsmasq.$app/" +ynh_secure_remove --file="/etc/hostapd/$app/" #================================================= # CLOSE A PORT #================================================= -if yunohost firewall list | grep -q "\- 547$" -then - ynh_script_progression --message="Closing port 547" - ynh_exec_warn_less yunohost firewall disallow TCP 547 -fi +if [[ -z "$(other_hotspot_apps)" ]]; then + if yunohost firewall list | grep -q "\- 547$"; then + ynh_script_progression --message="Closing port 547" + ynh_exec_warn_less yunohost firewall disallow TCP 547 + fi - -if yunohost firewall list | grep -q "\- 67$" -then - ynh_script_progression --message="Closing port 67" - ynh_exec_warn_less yunohost firewall disallow TCP 67 + if yunohost firewall list | grep -q "\- 67$"; then + ynh_script_progression --message="Closing port 67" + ynh_exec_warn_less yunohost firewall disallow TCP 67 + fi fi #================================================= diff --git a/scripts/restore b/scripts/restore index fb047d1..679bb30 100644 --- a/scripts/restore +++ b/scripts/restore @@ -29,12 +29,22 @@ app=$YNH_APP_INSTANCE_NAME firmware_nonfree=$(ynh_app_setting_get --app=$app --key=firmware_nonfree) service_name=$(ynh_app_setting_get --app=$app --key=service_name) +wifi_device=$(ynh_app_setting_get --app=$app --key=wifi_device) #================================================= # CHECK IF THE APP CAN BE RESTORED #================================================= ynh_script_progression --message="Validating restoration parameters..." +#================================================= +# FIND AND OPEN A PORT +#================================================= +ynh_script_progression --message="Configuring firewall..." + +# Update firewall for DHCP +ynh_exec_warn_less yunohost firewall allow --no-upnp --ipv6 UDP 547 +ynh_exec_warn_less yunohost firewall allow --no-upnp UDP 67 + # Meh idk where to put this ... On RPi, by default wlan is blocked if test -e /usr/sbin/rfkill && rfkill | grep wlan | grep -q -w 'blocked' then @@ -61,16 +71,23 @@ else pkg_dependencies="$pkg_dependencies $free_firmware_packages" fi -for FILE in $(ls /etc/hostapd/hostapd.conf{.tpl?,} 2>/dev/null) -do - ynh_restore_file --origin_path="$FILE" -done -ynh_restore_file --origin_path="/etc/dnsmasq.dhcpd/dhcpdv6.conf.tpl" -ynh_restore_file --origin_path="/etc/dnsmasq.dhcpd/dhcpdv4.conf.tpl" +ynh_restore_file --origin_path="/etc/hostapd/$app/hostapd.conf.tpl" +ynh_restore_file --origin_path="/etc/hostapd/$app/hostapd.conf" --not_mandatory + +ynh_restore_file --origin_path="/etc/dnsmasq.$app/dnsmasq.conf.tpl" +ynh_restore_file --origin_path="/etc/dnsmasq.d/$app.conf" --not_mandatory +systemctl restart dnsmasq + +ynh_restore_file --origin_path="/etc/dnsmasq.$app/dhcpdv6.conf.tpl" +ynh_restore_file --origin_path="/etc/dnsmasq.$app/dhcpdv6.conf" --not_mandatory + +ynh_restore_file --origin_path="/etc/dnsmasq.$app/dhcpdv4.conf.tpl" +ynh_restore_file --origin_path="/etc/dnsmasq.$app/dhcpdv4.conf" --not_mandatory ynh_restore_file --origin_path="/usr/local/bin/$service_name" -ynh_restore_file --origin_path="/etc/init.d/hostapd" +ynh_restore_file --origin_path="/etc/openvpn/scripts/route-up.d/90-${service_name}" +ynh_restore_file --origin_path="/etc/openvpn/scripts/route-down.d/90-${service_name}" #================================================= # SPECIFIC RESTORATION @@ -88,14 +105,14 @@ ynh_install_app_dependencies $pkg_dependencies ynh_script_progression --message="Restoring the systemd configuration..." ynh_restore_file --origin_path="/etc/systemd/system/$service_name.service" -systemctl enable $service_name.service --quiet +ynh_restore_file --origin_path="/etc/systemd/system/hostapd@$app.service" #================================================= # INTEGRATE SERVICE IN YUNOHOST #================================================= ynh_script_progression --message="Integrating service in YunoHost..." -yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd" +yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd@$app" #================================================= # START SYSTEMD SERVICE @@ -103,7 +120,10 @@ yunohost service add $service_name --description "Creates a Wi-Fi access point" ynh_script_progression --message="Starting a systemd service..." hot_reload_usb_wifi_cards -wifi_device=$(iw_devices | awk -F\| '{ print $1 }') +if [[ -z "$wifi_device" ]] || ! grep -q -F "$wifi_device" <(unused_iw_devices); then + wifi_device=$(unused_iw_devices | head -n 1) + ynh_app_setting_set --app=$app --key=wifi_device --value="${wifi_device}" +fi if [[ -z $wifi_device ]]; then ynh_app_setting_set --app=$app --key=service_enabled --value=0 diff --git a/scripts/upgrade b/scripts/upgrade index 519721e..1d56a39 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -19,6 +19,18 @@ app=$YNH_APP_INSTANCE_NAME firmware_nonfree=$(ynh_app_setting_get --app=$app --key=firmware_nonfree) service_name=$(ynh_app_setting_get --app=$app --key=service_name) +wifi_device=$(ynh_app_setting_get --app=$app --key=wifi_device) +wifi_ssid=$(ynh_app_setting_get --app=$app --key=wifi_ssid) +wifi_secure=$(ynh_app_setting_get --app=$app --key=wifi_secure) +wifi_passphrase=$(ynh_app_setting_get --app=$app --key=wifi_passphrase) +wifi_channel=$(ynh_app_setting_get --app=$app --key=wifi_channel) +advanced=$(ynh_app_setting_get --app=$app --key=advanced) +ip4_nat_prefix=$(ynh_app_setting_get --app=$app --key=ip4_nat_prefix) +ip6_net=$(ynh_app_setting_get --app=$app --key=ip6_net) +ip6_firewall=$(ynh_app_setting_get --app=$app --key=ip6_firewall) +dns=$(ynh_app_setting_get --app=$app --key=dns) +multissid=$(ynh_app_setting_get --app=$app --key=multissid) + #================================================= # CHECK VERSION #================================================= @@ -68,10 +80,68 @@ elif [ $firmware_nonfree = "no" ]; then fi if [ -z $service_name ]; then - service_name="ynh-hotspot" + service_name="ynh-$app" ynh_app_setting_set --app=$app --key=service_name --value=$service_name fi +if [[ -n "${multissid}" ]] && [[ "${multissid}" -gt 1 ]]; then + wifi_ssid=$(cut -d'|' -f 1 <<< ${wifi_ssid}) + wifi_secure=$(cut -d'|' -f 1 <<< ${wifi_secure}) + wifi_passphrase=$(cut -d'|' -f 1 <<< ${wifi_passphrase}) + advanced=$(cut -d'|' -f 1 <<< ${advanced}) + ip4_nat_prefix=$(cut -d'|' -f 1 <<< ${ip4_nat_prefix}) + ip6_net=$(cut -d'|' -f 1 <<< ${ip6_net}) + ip6_firewall=$(cut -d'|' -f 1 <<< ${ip6_firewall}) + dns=$(cut -d'|' -f 1 <<< ${dns}) + + ynh_app_setting_set --app=$app --key=wifi_ssid --value="${wifi_ssid}" + ynh_app_setting_set --app=$app --key=wifi_secure --value="${wifi_secure}" + ynh_app_setting_set --app=$app --key=wifi_passphrase --value="${wifi_passphrase}" + ynh_app_setting_set --app=$app --key=ip4_nat_prefix --value="${ip4_nat_prefix}" + ynh_app_setting_set --app=$app --key=ip6_net --value="${ip6_net}" + ynh_app_setting_set --app=$app --key=ip6_firewall --value="${ip6_firewall}" +fi + +if [[ -n "${dns}" ]]; then + ip6_dns="" + ip4_dns="" + for ip in $(echo "${dns}" | tr ',' ' '); do + if [[ "$ip" == *":"* ]]; then + ip6_dns+="[$ip]," + else + ip4_dns+="$ip," + fi + done + # Remove trailing , + ip6_dns="${ip6_dns%%,}" + ip4_dns="${ip4_dns%%,}" + + if [[ -z "$(ynh_app_setting_get --app=$app --key=ip6_dns)" ]]; then + ynh_app_setting_set --app=$app --key=ip6_dns --value="${ip6_dns}" + fi + if [[ -z "$(ynh_app_setting_get --app=$app --key=ip4_dns)" ]]; then + ynh_app_setting_set --app=$app --key=ip4_dns --value="${ip4_dns}" + fi + + ynh_app_setting_delete $app dns +else + ip6_dns=$(ynh_app_setting_get --app=$app --key=ip6_dns) + ip4_dns=$(ynh_app_setting_get --app=$app --key=ip4_dns) +fi + +if [[ -n "${multissid}" ]]; then + ynh_app_setting_delete --app=$app --key=multissid + + ynh_secure_remove --file="/etc/hostapd/hostapd.conf" + ynh_secure_remove --file="/etc/hostapd/hostapd.base.conf" + ynh_secure_remove --file="/etc/hostapd/hostapd.accesspoint.conf" + ynh_secure_remove --file="/etc/dnsmasq.dhcpd/" +fi + +if [[ -z "${advanced}" ]]; then + ynh_app_setting_set --app=$app --key=advanced --value=0 +fi + # Old stuff prior to 2.x ip6_net=$(ynh_app_setting_get --app=$app --key=ip6_net) @@ -131,15 +201,41 @@ ynh_install_app_dependencies $pkg_dependencies #================================================= ynh_script_progression --message="Copying configuration..." -mkdir -pm 0755 /etc/dnsmasq.dhcpd/ -chown root: /etc/dnsmasq.dhcpd/ +hot_reload_usb_wifi_cards +if [[ -z "$wifi_device" ]] || ! grep -q -F "$wifi_device" <(unused_iw_devices); then + wifi_device="$(unused_iw_devices | head -n 1)" + ynh_app_setting_set --app=$app --key=wifi_device --value="${wifi_device}" +fi -install -b -o root -g root -m 0644 ../conf/hostapd.*.conf /etc/hostapd/ -install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv6.conf.tpl /etc/dnsmasq.dhcpd/dhcpdv6.conf.tpl -install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv4.conf.tpl /etc/dnsmasq.dhcpd/dhcpdv4.conf.tpl +mkdir -pm 0755 /etc/hostapd/$app/ +chown root: /etc/hostapd/$app/ + +mkdir -pm 0755 /etc/dnsmasq.$app/ +chown root: /etc/dnsmasq.$app/ + +install -b -o root -g root -m 0644 ../conf/hostapd.conf.tpl /etc/hostapd/$app/hostapd.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq.conf.tpl /etc/dnsmasq.$app/dnsmasq.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv6.conf.tpl /etc/dnsmasq.$app/dhcpdv6.conf.tpl +install -b -o root -g root -m 0644 ../conf/dnsmasq_dhcpdv4.conf.tpl /etc/dnsmasq.$app/dhcpdv4.conf.tpl + +if [[ -n "${wifi_device}" ]]; then + configure_hostapd + configure_dnsmasq + configure_dhcp +fi # Copy init script -install -o root -g root -m 0755 ../conf/$service_name /usr/local/bin/ +ynh_add_config --template="../conf/ynh-hotspot" --destination="/usr/local/bin/$service_name" +chmod 0755 "/usr/local/bin/$service_name" + +# Copy openvpn scripts +mkdir -pm 0755 /etc/openvpn/scripts +mkdir -pm 0755 /etc/openvpn/scripts/route-up.d +mkdir -pm 0755 /etc/openvpn/scripts/route-down.d +ynh_add_config --template="../conf/openvpn_90-hotspot" --destination="/etc/openvpn/scripts/route-up.d/90-$service_name" +ynh_add_config --template="../conf/openvpn_90-hotspot" --destination="/etc/openvpn/scripts/route-down.d/90-$service_name" +chmod 0755 "/etc/openvpn/scripts/route-up.d/90-${service_name}" +chmod 0755 "/etc/openvpn/scripts/route-down.d/90-${service_name}" #================================================= # SETUP SYSTEMD @@ -148,6 +244,8 @@ ynh_script_progression --message="Upgrading systemd configuration..." # Create a dedicated systemd config ynh_add_systemd_config --service=$service_name +# Create custom systemd config for hostapd to handle multiple wifi devices +ynh_add_systemd_config --service="hostapd@$app" --template="../conf/systemd_hostapd.service" #================================================= # GENERIC FINALIZATION @@ -156,16 +254,13 @@ ynh_add_systemd_config --service=$service_name #================================================= ynh_script_progression --message="Integrating service in YunoHost..." -yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd" +yunohost service add $service_name --description "Creates a Wi-Fi access point" --test_status "systemctl is-active hostapd@$app" #================================================= # START SYSTEMD SERVICE #================================================= ynh_script_progression --message="Starting the hotspot service..." -hot_reload_usb_wifi_cards -wifi_device=$(iw_devices | awk -F\| '{ print $1 }') - if [[ -z $wifi_device ]]; then ynh_app_setting_set --app=$app --key=service_enabled --value=0 wifi_device=""