Initial commit

This commit is contained in:
Koray Yanik 2022-02-23 12:38:39 +00:00
commit 0a65725361
10 changed files with 327 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
status

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "bashserv"]
path = bashserv
url = https://github.com/fumyuun/bashserv.git

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Wakeboard
A simple status page to remotely wake up hosts, to use on a DHCP server using `dnsmasq`. It will read the leases as given out, and display all hosts that are statically configured, uses ping to figure out if they are awake or not, and can send a wake-on-lan packet to awake them.
It is likely full of security holes, so please ensure it is not accessable from an untrusted network :)

1
bashserv Submodule

@ -0,0 +1 @@
Subproject commit 797abde65eeecc327bdb577c75b05942716ef8ea

11
handle_404.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
body="<html>\n"
body+="<head><title>Not found</title></head>\n"
body+="<body>The requested resource $2 was not found</body>\n"
body+="</html>\n"
cat <<EOF
$($BASHSERV_DIR/header.sh -t "text/html" -l $(echo -ne "$body" | wc -c) 404)
$(echo -ne $body)
EOF

49
handle_get.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
echo "[$(date +%T)] GET $1 ($2)" >> get.log
./handle_requests.sh $@
if [ $? -eq 0 ]; then
exit 0
fi
if [ -z "$1" -o "$1" == "index.html" ]; then
body="<html>\n<head>\n<title>$WAKEBOARD_TITLE</title>\n<script type='text/javascript' src='main.js'></script>\n<link rel='stylesheet' href='main.css'></link>\n</head>\n"
body+="<body>\n<table>\n<tr><td></td><td>Hostname</td><td>IP Address</td><td>MAC Address</td><td>Wakeup</td></tr>\n"
IFS=$'\n'
leases=$(cat /var/lib/misc/dnsmasq.leases | cut -d ' ' -f2-4)
for lease in $leases; do
mac=$(echo $lease | cut -d ' ' -f1)
ip=$(echo $lease | cut -d ' ' -f2)
hostname=$(echo $lease | cut -d ' ' -f3)
if [ -n "$(grep -i "$mac" /etc/dnsmasq.conf)" ]; then
body+="<tr class='host' data-ip='$ip' data-mac='$mac'>\n"
body+="<td class='status'>"
body+="<div 'class='fail'>X</div>"
body+="<div class='success' style='display: none;'>&#10003;</div>"
body+="<div class='undef' style='display: none;'>?</div>"
body+="</td>\n"
body+="<td>$hostname</td>"
body+="<td>$ip</td>"
body+="<td>$mac</td>"
body+="<td><button class='wol'>Wake up!</button><td>\n"
body+="</tr>"
fi
done
body+="</table>\n</body>\n</html>\n"
cat <<EOF
$($BASHSERV_DIR/header.sh -t "text/html" -l $(echo -ne "$body" | wc -c))
$(echo -ne $body)
EOF
exit 0
fi
./handle_404.sh $@
exit $?

95
handle_requests.sh Executable file
View File

@ -0,0 +1,95 @@
#!/bin/bash
if [[ "$1" =~ ^refresh ]]; then
ip=$(echo "$1" | cut -d '/' -f2)
body="{\n\"time\": \"$(date +%T)\",\n"
body+="\"status\": \"unknown\"\n}\n"
cat <<EOF
$($BASHSERV_DIR/header.sh -t "application/json" -l $(echo -ne "$body" | wc -c))
$(echo -ne $body)
EOF
echo -ne "$body" > status/$ip
ret=1
for i in {0..30}; do
ping -c 1 -w 5 -t 1 -q "$ip"
ret=$?
[ $ret -eq 0 ] && break
done
echo -e "{\n\"time\": \"$(date +%T)\"," > status/$ip
if [ $ret -eq 0 ]; then
echo -e "\"status\": \"up\"\n}\n" >> status/$ip
else
echo -e "\"status\": \"down\"\n}\n" >> status/$ip
fi
exit 0
fi
if [[ "$1" =~ ^status ]]; then
ip=$(echo "$1" | cut -d '/' -f2)
if [ ! -r "status/$ip" ]; then
body="{\n\"status\": \"unknown\"\n}\n"
else
body=$(cat status/$ip)
fi
cat <<EOF
$($BASHSERV_DIR/header.sh -t "application/json" -l $(echo -e "$body" | wc -c))
$body
EOF
exit 0
fi
if [[ "$1" =~ ^quickping || "$1" =~ ^ping ]]; then
ip=$(echo "$1" | cut -d '/' -f2)
attempts=1
timeout=1
if [[ "$1" =~ ^ping ]]; then
attempts=30
timeout=5
fi
ret=1
for i in $(seq 1 $attempts); do
ping -c 1 -w $timeout -t 1 -q "$ip" > ping.log
ret=$?
[ $ret -eq 0 ] && break
done
if [ $ret -eq 0 ]; then
body="{\"response\": \"ok\"}\n"
else
body="{\"response: \"fail\"}\n"
fi
cat <<EOF
$($BASHSERV_DIR/header.sh -t "application/json" -l $(echo -ne "$body" | wc -c))
$(echo -ne $body)
EOF
exit 0
fi
if [[ "$1" =~ ^wol ]]; then
mac=$(echo "$1" | cut -d '/' -f2)
wol "$mac" > /dev/null
body="{\"response\": \"ok\"}\n"
cat <<EOF
$($BASHSERV_DIR/header.sh -t "application/json" -l $(echo -ne "$body" | wc -c))
$(echo -ne $body)
EOF
exit 0
fi
exit 1

7
static/main.css Normal file
View File

@ -0,0 +1,7 @@
body {
background: #aaaaaa;
}
table {
background: #bbbbbb;
}

112
static/main.js Normal file
View File

@ -0,0 +1,112 @@
var request_status = function (host) {
console.log("Update " + host.ip);
var request = new XMLHttpRequest();
request.addEventListener("load", function () {
var response;
console.log(this.status, this.responseText);
if (this.status !== 200) {
return;
}
response = JSON.parse(this.responseText);
if (response.status === "up") {
host.status_node.innerHTML = "&#10003;";
} else if (response.status === "unknown") {
setTimeout(function () {
request_status(host);
}, 1000);
} else {
host.status_node.innerHTML = "X";
}
});
request.open("GET", "status/" + host.ip);
request.send();
}
var request_refresh = function (host) {
console.log("Refresh " + host.ip);
var request = new XMLHttpRequest();
request.addEventListener("load", function () {
var response;
console.log(this.status, this.responseText);
if (this.status !== 200) {
return;
}
response = JSON.parse(this.responseText);
if (response.status === "ok") {
host.status_node.innerHTML = "&#10003;";
} else {
host.status_node.innerHTML = "X";
}
});
request.open("GET", "refresh/" + host.ip);
request.send();
setTimeout(function () {
request_status(host);
}, 1000);
}
var request_wol = function (host) {
console.log("Wakeup " + host.mac);
host.status_node.innerText = "?";
var request = new XMLHttpRequest();
request.addEventListener("load", function () {
var response;
console.log(this.status, this.responseText);
if (this.status !== 200) {
return;
}
response = JSON.parse(this.responseText);
if (response.response === "ok") {
host.status_node.innerHTML = "?";
} else {
host.status_node.innerHTML = "X";
}
});
request.open("GET", "wol/" + host.mac);
request.send();
setTimeout(function () {
request_refresh(host);
}, 1000);
}
window.onload = function () {
var host_nodes = document.getElementsByClassName('host');
var hosts = [];
var i;
if (host_nodes == undefined) {
return;
}
for (i = 0; i < host_nodes.length; i++) {
var host = {
ip : host_nodes[i].dataset.ip,
mac : host_nodes[i].dataset.mac
};
var status_node = host_nodes[i].getElementsByClassName('status');
var wol_button = host_nodes[i].getElementsByClassName('wol');
if (status_node == undefined || wol_button == undefined ||
status_node.length < 1 || wol_button.length < 1) {
return;
}
host.status_node = status_node[0];
host.wol_button = wol_button[0];
hosts.push(host);
(function (host_bound) {
host_bound.wol_button.onclick = function (e) {
request_wol(host_bound);
}
}) (host);
request_refresh(host);
}
}

42
wakeboard Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
WAKEBOARD_TITLE="Wakeboard"
PORT=8000
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-h|--help)
HELP=1
shift
;;
-p|--port)
PORT="$2"
shift
shift
;;
-t|--title)
WAKEBOARD_TITLE="$2"
shift
shift
;;
esac
done
if [ "$HELP" ]; then
echo "Usage: $0 [-h|--help] [-t|--title <title>] [-p|--port <port>]"
echo " -h | --help: Show this help"
echo " -t | --title: Title to give to the served page (defaults to Wakeboard)"
echo " -p | --port <port>: Port number to use (default 8000)"
exit 0
fi
if [ ! -d "status" ]; then
mkdir "status"
fi
# Ensure variable can be read by the get handler
export WAKEBOARD_TITLE
./bashserv/bashserv.sh -s "./static" -g "./handle_get.sh" -p "$PORT"