%
diff --git a/includes/hostapd.php b/includes/hostapd.php
index 93386c5e..f9bd53bc 100755
--- a/includes/hostapd.php
+++ b/includes/hostapd.php
@@ -57,11 +57,17 @@ function DisplayHostAPDConfig()
if (isset($_POST['StartHotspot']) || isset($_POST['RestartHotspot'])) {
$status->addMessage('Attempting to start hotspot', 'info');
if ($arrHostapdConf['BridgedEnable'] == 1) {
- exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface br0 --seconds 2', $return);
+ exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface br0 --seconds 1', $return);
} elseif ($arrHostapdConf['WifiAPEnable'] == 1) {
- exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface uap0 --seconds 2', $return);
+ exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface uap0 --seconds 1', $return);
} else {
- exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --seconds 2', $return);
+ // systemctl expects a unit name like raspap-network-activity@wlan0.service, no extra quotes
+ $iface_nonescaped = $_POST['interface'];
+ if (preg_match('/^[a-zA-Z0-9_-]+$/', $iface_nonescaped)) { // validate interface name
+ exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface ' .$iface_nonescaped. ' --seconds 1', $return);
+ } else {
+ throw new \Exception('Invalid network interface');
+ }
}
foreach ($return as $line) {
$status->addMessage($line, 'info');
@@ -69,6 +75,7 @@ function DisplayHostAPDConfig()
} elseif (isset($_POST['StopHotspot'])) {
$status->addMessage('Attempting to stop hotspot', 'info');
exec('sudo /bin/systemctl stop hostapd.service', $return);
+ exec('sudo systemctl stop "raspap-network-activity@*.service"');
foreach ($return as $line) {
$status->addMessage($line, 'info');
}
diff --git a/installers/common.sh b/installers/common.sh
index a6a56261..2b619304 100755
--- a/installers/common.sh
+++ b/installers/common.sh
@@ -75,6 +75,7 @@ function _update_raspap() {
_download_latest_files
_change_file_ownership
_patch_system_files
+ _enable_network_activity_monitor
_create_plugin_scripts
_install_complete
}
@@ -818,9 +819,38 @@ function _configure_networking() {
echo -e
_enable_raspap_daemon
fi
+
+ # Enable RaspAP network activity monitor
+ _enable_network_activity_monitor
+
_install_status 0
}
+# Install and enable RaspAP network activity monitor
+function _enable_network_activity_monitor() {
+ _install_log "Enabling RaspAP network activity monitor"
+ echo "Compiling raspap-network-monitor.c to /usr/local/bin/"
+ if ! command -v gcc >/dev/null 2>&1; then
+ echo "gcc not found, installing..."
+ sudo apt-get update
+ sudo apt-get install -y gcc || _install_status 1 "Failed to install gcc"
+ fi
+ sudo gcc -O2 -o /usr/local/bin/raspap-network-monitor $webroot_dir/installers/raspap-network-monitor.c || _install_status 1 "Failed to compile raspap-network-monitor.c"
+ echo "Copying raspap-network-activity@.service to /lib/systemd/system/"
+ sudo cp $webroot_dir/installers/raspap-network-activity@.service /lib/systemd/system/ || _install_status 1 "Unable to move raspap-network-activity.service file"
+ sudo systemctl daemon-reload
+ echo "Enabling raspap-network-activity@wlan0.service"
+ sudo systemctl enable raspap-network-activity@wlan0.service || _install_status 1 "Failed to enable raspap-network-activity.service"
+ echo "Starting raspap-network-activity@wlan0.service"
+ sudo systemctl start raspap-network-activity@wlan0.service || _install_status 1 "Failed to start raspap-network-activity.service"
+ sleep 0.5
+ echo "Symlinking /dev/shm/net_activity to $webroot_dir/app/net_activity"
+ sudo ln -sf /dev/shm/net_activity $webroot_dir/app/net_activity || _install_status 1 "Failed to link net_activity to ${webroot_dir}/app"
+ echo "Setting ownership for ${raspap_user} on ${webroot_dir}/app/net_activity"
+ sudo chown -R $raspap_user:$raspap_user $webroot_dir/app/net_activity || _install_status 1 "Unable to set ownership of ${webroot_dir}/app/net_activity"
+ echo "Network activity monitor enabled"
+}
+
# Prompt to configure TCP BBR option
function _prompt_configure_tcp_bbr() {
_install_log "Configure TCP BBR congestion control"
diff --git a/installers/raspap-network-activity@.service b/installers/raspap-network-activity@.service
new file mode 100644
index 00000000..615a7547
--- /dev/null
+++ b/installers/raspap-network-activity@.service
@@ -0,0 +1,15 @@
+# Author: BillZ
+
+[Unit]
+Description=RaspAP Network Activity Monitor for %I
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/raspap-network-monitor %i
+Restart=always
+RestartSec=2
+User=root
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/installers/raspap-network-monitor.c b/installers/raspap-network-monitor.c
new file mode 100644
index 00000000..93a556cf
--- /dev/null
+++ b/installers/raspap-network-monitor.c
@@ -0,0 +1,106 @@
+// raspap-network-monitor.c
+
+/*
+RaspAP Network Activity Monitor
+Author: @billz
+Author URI: https://github.com/billz/
+License: GNU General Public License v3.0
+License URI: https://github.com/raspap/raspap-webgui/blob/master/LICENSE
+
+Usage: raspap-network-monitor [interface]
+*/
+
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define TMPFILE "/dev/shm/net_activity"
+#define POLL_INTERVAL_MS 100 // 100 milliseconds
+
+unsigned long read_interface_bytes(const char *iface) {
+ FILE *fp = fopen("/proc/net/dev", "r");
+ if (!fp) return 0;
+
+ char line[512];
+ unsigned long rx = 0, tx = 0;
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (strstr(line, iface)) {
+ char *ptr = strchr(line, ':');
+ if (ptr) {
+ sscanf(ptr + 1, "%lu %*u %*u %*u %*u %*u %*u %*u %lu", &rx, &tx);
+ }
+ break;
+ }
+ }
+
+ fclose(fp);
+ return rx + tx;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s \n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ const char *iface = argv[1];
+ unsigned long prev_total = read_interface_bytes(iface);
+
+ // create a timerfd
+ int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (tfd == -1) {
+ perror("timerfd_create");
+ return EXIT_FAILURE;
+ }
+
+ struct itimerspec timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_nsec = POLL_INTERVAL_MS * 1000000; // interval
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_nsec = POLL_INTERVAL_MS * 1000000; // initial expiration
+
+ if (timerfd_settime(tfd, 0, &timer, NULL) == -1) {
+ perror("timerfd_settime");
+ close(tfd);
+ return EXIT_FAILURE;
+ }
+
+ struct pollfd fds;
+ fds.fd = tfd;
+ fds.events = POLLIN;
+
+ for (;;) {
+ int ret = poll(&fds, 1, -1);
+ if (ret == -1) {
+ perror("poll");
+ break;
+ }
+
+ if (fds.revents & POLLIN) {
+ uint64_t expirations;
+ read(tfd, &expirations, sizeof(expirations)); // clear timer
+
+ unsigned long curr_total = read_interface_bytes(iface);
+ unsigned long diff = (curr_total >= prev_total) ? (curr_total - prev_total) : 0;
+ prev_total = curr_total;
+
+ FILE *out = fopen(TMPFILE, "w");
+ if (out) {
+ fprintf(out, "%lu\n", diff);
+ fclose(out);
+ }
+ }
+ }
+
+ close(tfd);
+ return EXIT_SUCCESS;
+}
+
diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers
index c770a01b..9933cf18 100644
--- a/installers/raspap.sudoers
+++ b/installers/raspap.sudoers
@@ -80,3 +80,5 @@ www-data ALL=(ALL) NOPASSWD:/bin/truncate -s 0 /tmp/*.log,/bin/truncate -s 0 /va
www-data ALL=(ALL) NOPASSWD:/usr/bin/vnstat *
www-data ALL=(ALL) NOPASSWD:/usr/sbin/visudo -cf *
www-data ALL=(ALL) NOPASSWD:/etc/raspap/plugins/plugin_helper.sh
+www-data ALL=(ALL) NOPASSWD: /bin/systemctl start raspap-network-activity@*.service
+www-data ALL=(ALL) NOPASSWD: /bin/systemctl stop raspap-network-activity@*.service
diff --git a/installers/raspapd.service b/installers/raspapd.service
index c5738465..776cb16b 100644
--- a/installers/raspapd.service
+++ b/installers/raspapd.service
@@ -16,7 +16,7 @@ After=multi-user.target
[Service]
Type=oneshot
-ExecStart=/bin/bash /etc/raspap/hostapd/servicestart.sh --interface uap0 --seconds 3
+ExecStart=/bin/bash /etc/raspap/hostapd/servicestart.sh --seconds 1
RemainAfterExit=no
[Install]
diff --git a/installers/servicestart.sh b/installers/servicestart.sh
index 377678ca..157a41a4 100755
--- a/installers/servicestart.sh
+++ b/installers/servicestart.sh
@@ -34,6 +34,20 @@ esac
done
set -- "${positional[@]}"
+# Load config file into associative array
+declare -A config
+if [ -r "$CONFIGFILE" ]; then
+ while IFS=" = " read -r key value; do
+ config["$key"]="$value"
+ done < "$CONFIGFILE"
+fi
+
+# Set interface from config if not set by parameter
+if [ -z "$interface" ] && [ -n "${config[WifiInterface]}" ]; then
+ interface="${config[WifiInterface]}"
+ echo "Interface not provided. Using interface from config: $interface"
+fi
+
echo "Stopping network services..."
if [ $OPENVPNENABLED -eq 1 ]; then
systemctl stop openvpn-client@client
@@ -42,64 +56,58 @@ systemctl stop systemd-networkd
systemctl stop hostapd.service
systemctl stop dnsmasq.service
systemctl stop dhcpcd.service
+systemctl stop 'raspap-network-activity@*.service'
if [ "${action}" = "stop" ]; then
echo "Services stopped. Exiting."
exit 0
fi
-if [ -f "$DAEMONPATH" ] && [ ! -z "$interface" ]; then
+if [ -f "$DAEMONPATH" ] && [ -n "$interface" ]; then
echo "Changing RaspAP Daemon --interface to $interface"
sed -i "s/\(--interface \)[[:alnum:]]*/\1$interface/" "$DAEMONPATH"
fi
-if [ -r "$CONFIGFILE" ]; then
- declare -A config
- while IFS=" = " read -r key value; do
- config["$key"]="$value"
- done < "$CONFIGFILE"
+if [ "${config[BridgedEnable]}" = 1 ]; then
+ if [ "${interface}" = "br0" ]; then
+ echo "Stopping systemd-networkd"
+ systemctl stop systemd-networkd
- if [ "${config[BridgedEnable]}" = 1 ]; then
- if [ "${interface}" = "br0" ]; then
- echo "Stopping systemd-networkd"
- systemctl stop systemd-networkd
+ echo "Restarting eth0 interface..."
+ ip link set down eth0
+ ip link set up eth0
- echo "Restarting eth0 interface..."
- ip link set down eth0
- ip link set up eth0
+ echo "Removing uap0 interface..."
+ iw dev uap0 del
- echo "Removing uap0 interface..."
- iw dev uap0 del
+ echo "Enabling systemd-networkd"
+ systemctl start systemd-networkd
+ systemctl enable systemd-networkd
+ fi
+else
+ echo "Disabling systemd-networkd"
+ systemctl disable systemd-networkd
- echo "Enabling systemd-networkd"
- systemctl start systemd-networkd
- systemctl enable systemd-networkd
- fi
- else
- echo "Disabling systemd-networkd"
- systemctl disable systemd-networkd
+ ip link ls up | grep -q 'br0' &> /dev/null
+ if [ $? == 0 ]; then
+ echo "Removing br0 interface..."
+ ip link set down br0
+ ip link del dev br0
+ fi
- ip link ls up | grep -q 'br0' &> /dev/null
- if [ $? == 0 ]; then
- echo "Removing br0 interface..."
- ip link set down br0
- ip link del dev br0
- fi
+ if [ "${config[WifiAPEnable]}" = 1 ]; then
+ if [ "${interface}" = "uap0" ]; then
- if [ "${config[WifiAPEnable]}" = 1 ]; then
- if [ "${interface}" = "uap0" ]; then
-
- ip link ls up | grep -q 'uap0' &> /dev/null
- if [ $? == 0 ]; then
- echo "Removing uap0 interface..."
- iw dev uap0 del
- fi
-
- echo "Adding uap0 interface to ${config[WifiManaged]}"
- iw dev ${config[WifiManaged]} interface add uap0 type __ap
- # Bring up uap0 interface
- ifconfig uap0 up
+ ip link ls up | grep -q 'uap0' &> /dev/null
+ if [ $? == 0 ]; then
+ echo "Removing uap0 interface..."
+ iw dev uap0 del
fi
+
+ echo "Adding uap0 interface to ${config[WifiManaged]}"
+ iw dev ${config[WifiManaged]} interface add uap0 type __ap
+ # Bring up uap0 interface
+ ifconfig uap0 up
fi
fi
fi
@@ -114,12 +122,13 @@ sleep "${seconds}"
systemctl start dnsmasq.service
+echo "Starting raspap-network-activity@${interface}.service"
+systemctl start raspap-network-activity@${interface}.service
+
if [ $OPENVPNENABLED -eq 1 ]; then
systemctl start openvpn-client@client
fi
-# @mp035 found that the wifi client interface would stop every 8 seconds
-# for about 16 seconds. Reassociating seems to solve this
if [ "${config[WifiAPEnable]}" = 1 ]; then
echo "Reassociating wifi client interface..."
sleep "${seconds}"
diff --git a/templates/dashboard.php b/templates/dashboard.php
index c7db88f0..29b217b5 100755
--- a/templates/dashboard.php
+++ b/templates/dashboard.php
@@ -20,7 +20,7 @@
diff --git a/templates/hostapd.php b/templates/hostapd.php
index ccdc1a62..746034b6 100755
--- a/templates/hostapd.php
+++ b/templates/hostapd.php
@@ -40,7 +40,7 @@