mirror of
https://github.com/YunoHost-Apps/hotspot_ynh.git
synced 2024-09-03 19:25:53 +02:00
* Automatic detection of the interface
* Automatic detection of wifi n * Checking inputs
This commit is contained in:
parent
7f9ceea21a
commit
1f9d32d74d
10 changed files with 187 additions and 61 deletions
|
@ -1,10 +1,8 @@
|
|||
# Hotspot Wifi
|
||||
# Wifi Hotspot
|
||||
## Overview
|
||||
|
||||
**Warning: work in progress**
|
||||
|
||||
**Warning: currently, there is no checking on input parameters, so be careful**
|
||||
|
||||
Hotspot wifi app for [YunoHost](http://yunohost.org/).
|
||||
|
||||
* Broadcast your own Wifi internet access in addition to your self-hosted web services.
|
||||
|
@ -14,10 +12,9 @@ Hotspot wifi app for [YunoHost](http://yunohost.org/).
|
|||
## Features
|
||||
|
||||
* WPA2 encryption
|
||||
* 802.11n if your antenna is compliant
|
||||
* 802.11n compliant
|
||||
* IPv6 compliant (with a delegated prefix)
|
||||
* Automatic clients configuration (IPv6 and IPv4)
|
||||
* Announce DNS resolvers (IPv6 and IPv4)
|
||||
* Set an IPv6 from your delegated prefix (*prefix::1*) on the server, to use for the AAAA records
|
||||
* The internet provider can be a 3/4G connection with tethering
|
||||
* Set an IPv6 from your delegated prefix (*prefix::42*) on the server, to use for the AAAA records
|
||||
* Web interface ([screenshot](https://raw.githubusercontent.com/jvaubourg/hotspot_ynh/master/screenshot.png))
|
||||
|
|
1
TODO
1
TODO
|
@ -2,3 +2,4 @@
|
|||
** in bash install script (empty parameters, passphrase size and allowed characters with WPA2, is Wifi device exist)
|
||||
** in PHP controller (empty parameters, parameters format, compressed IPv6, NAT address format, passphrase size and allowed characters with WPA2)
|
||||
* Translate PHP interface in French
|
||||
** Add require for slapd for the service start
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: ynh-hotspot
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Start: $network $remote_fs $syslog $all
|
||||
# Required-Stop: $network $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
|
@ -12,6 +12,10 @@
|
|||
# Functions
|
||||
## State functions
|
||||
|
||||
has_vpnclient_app() {
|
||||
[ -e /tmp/.ynh-vpnclient-started ]
|
||||
}
|
||||
|
||||
has_ip6delegatedprefix() {
|
||||
[ "${ynh_ip6_net}" != none ]
|
||||
}
|
||||
|
@ -77,6 +81,7 @@ set_ip4nataddr() {
|
|||
}
|
||||
|
||||
set_ip6addr() {
|
||||
ip address delete "${ynh_ip6_addr}/64" dev tun0 &> /dev/null
|
||||
ip address add "${ynh_ip6_addr}/64" dev "${ynh_wifi_device}"
|
||||
}
|
||||
|
||||
|
@ -223,7 +228,14 @@ case "$1" in
|
|||
if is_running; then
|
||||
echo "Already started"
|
||||
else
|
||||
echo "Starting..."
|
||||
echo "[hotspot] Starting..."
|
||||
touch /tmp/.ynh-hotspot-started
|
||||
|
||||
if [ "${new_internet_device}" == tun0 ]; then
|
||||
moulinette_set vpnclient yes
|
||||
else
|
||||
moulinette_set vpnclient no
|
||||
fi
|
||||
|
||||
# Set NDP proxy
|
||||
if has_ip6delegatedprefix && ! is_ndproxy_set; then
|
||||
|
@ -282,13 +294,20 @@ case "$1" in
|
|||
echo "Run dhcpd"
|
||||
start_dhcpd
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update dynamic settings
|
||||
moulinette_set internet_device "${new_internet_device}"
|
||||
fi
|
||||
|
||||
# Restart php5-fpm at the first start (it needs to be restarted after the slapd start)
|
||||
if [ ! -e /tmp/.ynh-hotspot-boot ]; then
|
||||
touch /tmp/.ynh-hotspot-boot
|
||||
service php5-fpm restart
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping..."
|
||||
echo "[hotspot] Stopping..."
|
||||
rm /tmp/.ynh-hotspot-started
|
||||
|
||||
if has_ip6delegatedprefix && is_ndproxy_set; then
|
||||
echo "Unset NDP proxy"
|
||||
|
@ -329,6 +348,10 @@ case "$1" in
|
|||
echo "Stop dhcpd"
|
||||
stop_dhcpd
|
||||
fi
|
||||
|
||||
if has_vpnclient_app; then
|
||||
service ynh-vpnclient start
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
exitcode=0
|
||||
|
|
3
conf/ipv6_compressed
Normal file
3
conf/ipv6_compressed
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
sipcalc "${1}" | grep Compressed | awk '{ print $NF; }'
|
3
conf/ipv6_expanded
Normal file
3
conf/ipv6_expanded
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
sipcalc "${1}" | grep Expanded | awk '{ print $NF; }'
|
|
@ -48,15 +48,6 @@
|
|||
},
|
||||
"example": "VhegT8oev0jZI"
|
||||
},
|
||||
{
|
||||
"name": "wifi_device",
|
||||
"ask": {
|
||||
"en": "Select the wifi antenna interface",
|
||||
"fr": "Sélectionnez l'interface correspondant à l'antenne wifi"
|
||||
},
|
||||
"example": "wlan0",
|
||||
"default": "wlan0"
|
||||
},
|
||||
{
|
||||
"name": "ip6_net",
|
||||
"ask": {
|
||||
|
|
|
@ -1,16 +1,31 @@
|
|||
#wifiadmin!/bin/bash
|
||||
#!/bin/bash
|
||||
|
||||
# Retrieve arguments
|
||||
domain=${1}
|
||||
url_path=${2}
|
||||
wifi_ssid=${3}
|
||||
wifi_passphrase=${4}
|
||||
wifi_device=${5}
|
||||
ip6_net=${6}
|
||||
ip6_net=${5}
|
||||
|
||||
# Check arguments
|
||||
# TODO
|
||||
if [ -z "${wifi_ssid}" -o -z "${wifi_passphrase}" ]; then
|
||||
echo "ERROR: Your Wifi Hotspot needs a name and a password" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
wifi_passphrase_length="$(echo -n "${wifi_passphrase}" | wc -c)"
|
||||
if [ "${wifi_passphrase_length}" -lt 8 -o "${wifi_passphrase_length}" -gt 63 ]; then
|
||||
echo "ERROR: Your password must from 8 to 63 characters (WPA2 passphrase)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "${wifi_passphrase}" | grep -qP '[^[:print:]]'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "ERROR: Only printable ASCII characters are permitted in your password (WPA2 passphrase)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check domain/path availability
|
||||
sudo yunohost app checkurl ${domain}${url_path} -a hotspot
|
||||
if [ ! $? -eq 0 ]; then
|
||||
exit 1
|
||||
|
@ -19,20 +34,40 @@ fi
|
|||
# Install packages
|
||||
# TODO: Replace isc-dhcp-server by dnsmasq (currently negotiating with the YunoHost team to
|
||||
# also replace bind9 by dnsmasq)
|
||||
#sudo apt-get update
|
||||
sudo apt-get --assume-yes --force-yes install hostapd radvd isc-dhcp-server iptables php5-fpm
|
||||
|
||||
# Install extra packages
|
||||
sudo apt-get --assume-yes --force-yes install sipcalc
|
||||
# Extra packages
|
||||
sudo apt-get --assume-yes --force-yes install sipcalc iwconfig
|
||||
|
||||
# Compute extra arguments
|
||||
if [ -z "${ip6_net}" ]; then
|
||||
ip6_net=none
|
||||
ip6_addr=none
|
||||
else
|
||||
ip6_expanded_net=$(sipcalc "${ip6_net}" | grep Expanded | awk '{ print $NF; }')
|
||||
ip6_net=$(sipcalc "${ip6_net}" | grep Compressed | awk '{ print $NF; }')
|
||||
ip6_addr=$(echo "$(echo "${ip6_expanded_net}" | cut -d: -f1-7):1")
|
||||
ip6_addr=$(sipcalc "${ip6_addr}" | grep Compressed | awk '{ print $NF; }')
|
||||
ip6_net=$(bash ../conf/ipv6_expanded "${ip6_net}")
|
||||
|
||||
if [ -z "${ip6_net}" ]; then
|
||||
echo "ERROR: The IPv6 Delegated Prefix format looks bad" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ip6_addr="$(echo "${ip6_net}" | cut -d: -f1-7):42"
|
||||
ip6_net=$(bash ../conf/ipv6_compressed "${ip6_net}")
|
||||
ip6_addr=$(bash ../conf/ipv6_compressed "${ip6_addr}")
|
||||
fi
|
||||
|
||||
wifi_device=$(sudo iwconfig 2>&1 | grep 802.11 | head -n1 | awk '{ print $1 }')
|
||||
wifi_n=0
|
||||
|
||||
if [ -z "${wifi_device}" ]; then
|
||||
echo "ERROR: No wifi interface found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo iwconfig "${wifi_device}" | grep -q 'n *ESSID'
|
||||
if [ $? -eq 0 ]; then
|
||||
wifi_n=1
|
||||
fi
|
||||
|
||||
# Save arguments
|
||||
|
@ -40,7 +75,7 @@ sudo yunohost app setting hotspot wifi_ssid -v "${wifi_ssid}"
|
|||
sudo yunohost app setting hotspot wifi_passphrase -v "${wifi_passphrase}"
|
||||
sudo yunohost app setting hotspot wifi_device -v "${wifi_device}"
|
||||
sudo yunohost app setting hotspot wifi_channel -v 6
|
||||
sudo yunohost app setting hotspot wifi_n -v 0
|
||||
sudo yunohost app setting hotspot wifi_n -v "${wifi_n}"
|
||||
sudo yunohost app setting hotspot ip6_addr -v "${ip6_addr}"
|
||||
sudo yunohost app setting hotspot ip6_net -v "${ip6_net}"
|
||||
sudo yunohost app setting hotspot ip6_dns0 -v 2001:913::8
|
||||
|
@ -48,6 +83,11 @@ sudo yunohost app setting hotspot ip6_dns1 -v 2001:910:800::12
|
|||
sudo yunohost app setting hotspot ip4_dns0 -v 80.67.188.188
|
||||
sudo yunohost app setting hotspot ip4_dns1 -v 80.67.169.12
|
||||
sudo yunohost app setting hotspot ip4_nat_prefix -v 10.0.242
|
||||
sudo yunohost app setting hotspot vpnclient -v no
|
||||
|
||||
# Install IPv6 scripts
|
||||
sudo install -o root -g root -m 0755 ../conf/ipv6_expanded /usr/local/bin/
|
||||
sudo install -o root -g root -m 0755 ../conf/ipv6_compressed /usr/local/bin/
|
||||
|
||||
# Copy confs
|
||||
sudo install -b -o root -g root -m 0644 ../conf/hostapd.conf.tpl /etc/hostapd/
|
||||
|
|
|
@ -7,6 +7,7 @@ domain=$(sudo yunohost app setting hotspot domain)
|
|||
sudo service ynh-hotspot stop
|
||||
sudo yunohost service remove ynh-hotspot
|
||||
sudo rm -f /etc/init.d/ynh-hotspot
|
||||
sudo rm -f /tmp/.ynh-hotspot-boot
|
||||
|
||||
# Remove confs
|
||||
sudo rm -f /etc/hostapd/hostapd.conf{.tpl,} /etc/radvd.conf{.tpl,} /etc/dhcp/dhcpd.conf{.tpl,}
|
||||
|
@ -24,17 +25,9 @@ sudo rm -rf /var/www/wifiadmin/
|
|||
# Remove user
|
||||
sudo userdel -f wifiadmin
|
||||
|
||||
# Restart vpnclient service if installed to set the IPv6 address
|
||||
# A new start will fix the address without unsetting all stuff
|
||||
sudo yunohost app list -f vpnclient --json | grep -q '"installed": true'
|
||||
if [ "$?" -eq 0 ]; then
|
||||
sudo service ynh-vpnclient start
|
||||
fi
|
||||
|
||||
|
||||
# Remove packets
|
||||
# The yunohost policy is currently to not uninstall packets (dependency problems)
|
||||
## sudo apt-get --assume-yes --force-yes remove hostapd radvd isc-dhcp-server iptables
|
||||
## sudo apt-get --assume-yes --force-yes remove sipcalc
|
||||
## sudo apt-get --assume-yes --force-yes remove sipcalc iwconfig
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
function moulinette_get($var) {
|
||||
return htmlspecialchars(exec("sudo yunohost app setting hotspot ".escapeshellarg($var)));
|
||||
return htmlspecialchars(exec('sudo yunohost app setting hotspot '.escapeshellarg($var)));
|
||||
}
|
||||
|
||||
function moulinette_set($var, $value) {
|
||||
return exec("sudo yunohost app setting hotspot ".escapeshellarg($var)." -v ".escapeshellarg($value));
|
||||
return exec('sudo yunohost app setting hotspot '.escapeshellarg($var).' -v '.escapeshellarg($value));
|
||||
}
|
||||
|
||||
function stop_service() {
|
||||
|
@ -18,22 +18,32 @@ function start_service() {
|
|||
return $retcode;
|
||||
}
|
||||
|
||||
function ipv6_expanded($ip) {
|
||||
exec('ipv6_expanded '.escapeshellarg($ip), $output);
|
||||
|
||||
return $output[0];
|
||||
}
|
||||
|
||||
function ipv6_compressed($ip) {
|
||||
exec('ipv6_compressed '.escapeshellarg($ip), $output);
|
||||
|
||||
return $output[0];
|
||||
}
|
||||
|
||||
dispatch('/', function() {
|
||||
exec('ip link', $devs);
|
||||
exec('sudo iwconfig', $devs);
|
||||
$wifi_device = moulinette_get('wifi_device');
|
||||
$devs_list = "";
|
||||
|
||||
foreach($devs AS $dev) {
|
||||
if(preg_match('/^[0-9]/', $dev)) {
|
||||
$dev = explode(':', $dev);
|
||||
$dev = trim($dev[1]);
|
||||
if(preg_match('/802.11/', $dev)) {
|
||||
$dev = explode(' ', $dev);
|
||||
$dev = $dev[0];
|
||||
|
||||
if($dev != 'lo') {
|
||||
$active = ($dev == $wifi_device) ? 'class="active"' : '';
|
||||
$devs_list .= "<li $active><a href='#'>$dev</a></li>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ip6_net = moulinette_get('ip6_net');
|
||||
$ip6_net = ($ip6_net == 'none') ? '' : $ip6_net;
|
||||
|
@ -55,7 +65,78 @@ dispatch('/', function() {
|
|||
});
|
||||
|
||||
dispatch_put('/settings', function() {
|
||||
exec('ip link show '.escapeshellarg($_POST['wifi_device']), $output, $retcode);
|
||||
$wifi_device_exists = ($retcode == 0);
|
||||
|
||||
$ip6_net = empty($_POST['ip6_net']) ? 'none' : $_POST['ip6_net'];
|
||||
$ip6_addr = 'none';
|
||||
|
||||
try {
|
||||
if(empty($_POST['wifi_ssid']) || empty($_POST['wifi_passphrase']) || empty($_POST['wifi_channel'])) {
|
||||
throw new Exception(T_('Your Wifi Hotspot needs a name, a password and a channel'));
|
||||
}
|
||||
|
||||
if(strlen($_POST['wifi_passphrase']) < 8 || strlen($_POST['wifi_passphrase']) > 63) {
|
||||
throw new Exception(T_('Your password must from 8 to 63 characters (WPA2 passphrase)'));
|
||||
}
|
||||
|
||||
if(preg_match('/[^[:print:]]/', $_POST['wifi_passphrase'])) {
|
||||
throw new Exception(T_('Only printable ASCII characters are permitted in your password'));
|
||||
}
|
||||
|
||||
if(!$wifi_device_exists) {
|
||||
throw new Exception(T_('The wifi antenna interface seems not exist on the system'));
|
||||
}
|
||||
|
||||
if($ip6_net != 'none') {
|
||||
$ip6_net = ipv6_expanded($ip6_net);
|
||||
|
||||
if(empty($ip6_net)) {
|
||||
throw new Exception(T_('The IPv6 Delegated Prefix format looks bad'));
|
||||
}
|
||||
|
||||
$ip6_blocs = explode(':', $ip6_net);
|
||||
$ip6_addr = "${ip6_blocs[0]}:${ip6_blocs[1]}:${ip6_blocs[2]}:${ip6_blocs[3]}:${ip6_blocs[4]}:${ip6_blocs[5]}:${ip6_blocs[6]}:42";
|
||||
|
||||
$ip6_net = ipv6_compressed($ip6_net);
|
||||
$ip6_addr = ipv6_compressed($ip6_addr);
|
||||
}
|
||||
|
||||
$ip6_dns0 = ipv6_expanded($ip6_dns0);
|
||||
|
||||
if(empty($_POST['ip6_dns0'])) {
|
||||
throw new Exception(T_('The format of the first IPv6 DNS Resolver looks bad'));
|
||||
}
|
||||
|
||||
$ip6_dns0 = ipv6_compressed($ip6_dns0);
|
||||
$ip6_dns1 = ipv6_expanded($ip6_dns1);
|
||||
|
||||
if(empty($_POST['ip6_dns1'])) {
|
||||
throw new Exception(T_('The format of the second IPv6 DNS Resolver looks bad'));
|
||||
}
|
||||
|
||||
$ip6_dns1 = ipv6_compressed($ip6_dns1);
|
||||
|
||||
if(inet_pton($_POST['ip4_dns0']) === false) {
|
||||
throw new Exception(T_('The format of the first IPv4 DNS Resolver looks bad'));
|
||||
}
|
||||
|
||||
if(inet_pton($_POST['ip4_dns1']) === false) {
|
||||
throw new Exception(T_('The format of the second IPv4 DNS Resolver looks bad'));
|
||||
}
|
||||
|
||||
if(inet_pton("${_POST['ip4_nat_prefix']}.0") === false) {
|
||||
throw new Exception(T_('The format of the IPv4 NAT Prefix (/24) looks bad : x.x.x expected)'));
|
||||
}
|
||||
|
||||
if(filter_var("${_POST['ip4_nat_prefix']}.0", FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) !== false) {
|
||||
throw new Exception(T_('The IPv4 NAT Prefix must be from a private range'));
|
||||
}
|
||||
|
||||
} catch(Exception $e) {
|
||||
flash('error', $e->getMessage().T_(' (configuration not updated).'));
|
||||
goto redirect;
|
||||
}
|
||||
|
||||
stop_service();
|
||||
|
||||
|
@ -65,20 +146,13 @@ dispatch_put('/settings', function() {
|
|||
moulinette_set('wifi_n', isset($_POST['wifi_n']) ? 1 : 0);
|
||||
moulinette_set('wifi_device', $_POST['wifi_device']);
|
||||
moulinette_set('ip6_net', $ip6_net);
|
||||
moulinette_set('ip6_addr', $ip6_addr);
|
||||
moulinette_set('ip6_dns0', $_POST['ip6_dns0']);
|
||||
moulinette_set('ip6_dns1', $_POST['ip6_dns1']);
|
||||
moulinette_set('ip4_nat_prefix', $_POST['ip4_nat_prefix']);
|
||||
moulinette_set('ip4_dns0', $_POST['ip4_dns0']);
|
||||
moulinette_set('ip4_dns1', $_POST['ip4_dns1']);
|
||||
|
||||
# TODO: format ip6_net
|
||||
if($ip6_net == 'none') {
|
||||
moulinette_set('ip6_addr', 'none');
|
||||
} else {
|
||||
$ip6_addr = "${ip6_net}1";
|
||||
moulinette_set('ip6_addr', $ip6_addr);
|
||||
}
|
||||
|
||||
$retcode = start_service();
|
||||
|
||||
if($retcode == 0) {
|
||||
|
@ -87,6 +161,7 @@ dispatch_put('/settings', function() {
|
|||
flash('error', T_('Configuration updated but service reload failed'));
|
||||
}
|
||||
|
||||
redirect:
|
||||
redirect_to('/');
|
||||
});
|
||||
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
<div style="padding: 14px 14px 0 10px">
|
||||
<div class="form-group">
|
||||
<label for="wifi_ssid" class="col-sm-3 control-label"><?= T_('SSID') ?></label>
|
||||
<label for="wifi_ssid" class="col-sm-3 control-label"><?= T_('Name (SSID)') ?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="wifi_ssid" id="wifi_ssid" placeholder="myNeutralNetwork" value="<?= $wifi_ssid ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="wifi_passphrase" class="col-sm-3 control-label"><?= T_('Passphrase (WPA2)') ?></label>
|
||||
<label for="wifi_passphrase" class="col-sm-3 control-label"><?= T_('Password (WPA2)') ?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" data-toggle="tooltip" data-title="<?= T_('At least 8 characters') ?>" class="form-control" name="wifi_passphrase" id="wifi_passphrase" placeholder="VhegT8oev0jZI" value="<?= $wifi_passphrase ?>" />
|
||||
</div>
|
||||
|
@ -84,7 +84,7 @@
|
|||
<div class="alert alert-dismissible alert-warning fade in" style="margin: 2px 2px 17px" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<strong><?= T_('Notice') ?>:</strong> <?= T_("Currently, your wifi clients don't have IPv6 and it's a very bad thing. Ask your Internet Service Provider an IPv6 delegated prefix, or") ?>
|
||||
<a href="http://db.ffdn.org" class="alert-link"><?= T_('change providers') ?></a> !</span>
|
||||
<a href="http://db.ffdn.org" class="alert-link"><?= T_('change providers') ?></a>!
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
|
Loading…
Reference in a new issue