#!/bin/sh
# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
# License; GPL v3
SCRIPT_VERSION="48"
test -f /tmp/started || exit
#Get the configuration from the uci configuration file
#If it does not exists, then get it from a normal bash file with variables.
if [ -f /etc/config/nodewatcher ];then
SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
else
. "$(dirname "$0")/nodewatcher_config"
fi
if [ "$SCRIPT_ERROR_LEVEL" -gt "1" ]; then
err() {
echo "$1" >> "$SCRIPT_LOGFILE"
}
else
err() {
:
}
fi
#This method checks if the log file has become too big and deletes the first X lines
delete_log() {
if [ -f "$SCRIPT_LOGFILE" ]; then
if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
sed -i '1,60d' "$SCRIPT_LOGFILE"
err "$(date): Logfile has been made smaller"
fi
fi
}
inArray() {
local value
for value in $1; do
if [ "$value" = "$2" ]; then
return 0
fi
done
return 1
}
#This method generates the crawl data XML file that is being fetched by netmon
#and provided by a small local httpd
crawl() {
#Get system data from other locations
err "$(date): Collecting basic system status data"
hostname="$(cat /proc/sys/kernel/hostname)"
mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
[ "$hostname" = "LEDE" ] && hostname="$mac"
[ "$hostname" = "FFF" ] && hostname="$mac"
description="$(uci -q get fff.system.description)"
if [ -n "$description" ]; then
description=""
fi
latitude="$(uci -q get fff.system.latitude)"
longitude="$(uci -q get fff.system.longitude)"
if [ -n "$longitude" -a -n "$latitude" ]; then
geo="$latitude$longitude";
fi
position_comment="$(uci -q get fff.system.position_comment)"
if [ -n "$position_comment" ]; then
position_comment=""
fi
contact="$(uci -q get fff.system.contact)"
if [ -n "$contact" ]; then
contact="$contact"
fi
uptime=$(awk '{ printf ""$1""$2"" }' /proc/uptime)
memory=$(awk '
/^MemTotal/ { printf ""$2"" }
/^Cached:/ { printf ""$2"" }
/^Buffers/ { printf ""$2"" }
/^MemFree/ { printf ""$2"" }
' /proc/meminfo)
cpu=$(awk -F': ' '
/model/ { printf ""$2"" }
/system type/ { printf ""$2"" }
/platform/ { printf ""$2"" }
' /proc/cpuinfo)
model="$(cat /var/sysinfo/model)"
local_time="$(date +%s)"
load=$(awk '{ printf ""$3""$4"" }' /proc/loadavg)
err "$(date): Collecting version information"
batman_adv_version=$(cat /sys/module/batman_adv/version)
kernel_version=$(uname -r)
if [ -x /usr/bin/fastd ]; then
fastd_version="$(/usr/bin/fastd -v | awk '{ print $2 }')"
fi
nodewatcher_version=$SCRIPT_VERSION
if [ -f "$SCRIPT_STATUS_FILE" ]; then
status_text="$(cat "$SCRIPT_STATUS_FILE")"
fi
#Checks whether either fastd or L2TP is connected
if pidof fastd >/dev/null || grep -q '1' /sys/class/net/l2tp*/carrier 2> /dev/null ; then
vpn_active="1"
else
vpn_active="0"
fi
# example for /etc/openwrt_release:
#DISTRIB_ID="OpenWrt"
#DISTRIB_RELEASE="Attitude Adjustment"
#DISTRIB_REVISION="r35298"
#DISTRIB_CODENAME="attitude_adjustment"
#DISTRIB_TARGET="atheros/generic"
#DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
. /etc/openwrt_release
distname=$DISTRIB_ID
distversion=$DISTRIB_RELEASE
# example for /etc/firmware_release:
#FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
#BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
#OPENWRT_CORE_REVISION="35298"
#OPENWRT_FEEDS_PACKAGES_REVISION="35298"
. /etc/firmware_release
SYSTEM_DATA="online"
SYSTEM_DATA=$SYSTEM_DATA"$status_text"
SYSTEM_DATA=$SYSTEM_DATA"$hostname"
SYSTEM_DATA=$SYSTEM_DATA"${description}"
SYSTEM_DATA=$SYSTEM_DATA"${geo}"
SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
SYSTEM_DATA=$SYSTEM_DATA"${contact}"
if [ "$(uci -q get "system.@system[0].hood")" ]
then
SYSTEM_DATA=$SYSTEM_DATA"$(uci -q get "system.@system[0].hood")"
fi
SYSTEM_DATA=$SYSTEM_DATA"$distname"
SYSTEM_DATA=$SYSTEM_DATA"$distversion"
SYSTEM_DATA=$SYSTEM_DATA"$cpu"
SYSTEM_DATA=$SYSTEM_DATA"$model"
SYSTEM_DATA=$SYSTEM_DATA"$memory"
SYSTEM_DATA=$SYSTEM_DATA"$load"
SYSTEM_DATA=$SYSTEM_DATA"$uptime"
SYSTEM_DATA=$SYSTEM_DATA"$local_time"
SYSTEM_DATA=$SYSTEM_DATA"$batman_adv_version"
SYSTEM_DATA=$SYSTEM_DATA"$kernel_version"
SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
SYSTEM_DATA=$SYSTEM_DATA"$nodewatcher_version"
SYSTEM_DATA=$SYSTEM_DATA"$FIRMWARE_VERSION"
SYSTEM_DATA=$SYSTEM_DATA"$BUILD_DATE"
SYSTEM_DATA=$SYSTEM_DATA"$OPENWRT_CORE_REVISION"
SYSTEM_DATA=$SYSTEM_DATA"$OPENWRT_FEEDS_PACKAGES_REVISION"
SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
err "$(date): Collecting information from network interfaces"
#Get interfaces
interface_data=""
#Loop interfaces
#for entry in $IFACES; do
for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
ifpath=${filename%/operstate*}
iface=${ifpath#/sys/class/net/}
if inArray "$IFACEBLACKLIST" "$iface"; then
continue
fi
#Get interface data for whitelisted interfaces
# shellcheck disable=SC2016
awkscript='
/ether/ { printf ""$2"" }
/mtu/ { printf ""$5"" }'
if inArray "$IPWHITELIST" "$iface"; then
# shellcheck disable=SC2016
awkscript=$awkscript'
/inet / { split($2, a, "/"); printf ""a[1]"" }
/inet6/ && /scope global/ { printf ""$2"" }
/inet6/ && /scope link/ { printf ""$2""}'
fi
addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
interface_data=$interface_data"<$iface>$iface$addrs$traffic_rx$traffic_tx"
interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
/Mode/{ split($2, m, " "); printf ""m[1]"" }
/Cell/{ split($0, c, " "); printf ""c[5]"" }
/ESSID/ { split($0, e, "\""); printf ""e[2]"" }
/Freq/{ split($3, f, " "); printf ""f[1]f[2]"" }
/Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf ""p[2]"" }
')
interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
/ssid/{ split($0, s, " "); printf ""s[2]"" }
/type/ { split($0, t, " "); printf ""t[2]"" }
/channel/{ split($0, c, " "); printf ""c[2]"" }
/width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf ""w[2]"" }
')
interface_data=$interface_data"$iface>"
done
err "$(date): Collecting information from batman advanced and its interfaces"
#B.A.T.M.A.N. advanced
if [ -f /sys/module/batman_adv/version ]; then
for iface in $(grep active /sys/class/net/*/batman_adv/iface_status); do
status=${iface#*:}
iface=${iface%/batman_adv/iface_status:active}
iface=${iface#/sys/class/net/}
BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface>$iface$status$iface>"
done
# Build a list of direct neighbors
batman_adv_originators=$(awk \
'BEGIN { FS=" "; i=0 } # set the delimiter to " "
/O/ { next } # ignore lines with O (will remove second line)
/B/ { next } # ignore line with B (will remove first line)
{ sub("\\(", "", $0) # remove parentheses
sub("\\)", "", $0)
sub("\\[", "", $0)
sub("\\]:", "", $0)
sub(" ", " ", $0)
o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
{
printf ""$1""$3""$4""$2""$5""
i++
}
}' /sys/kernel/debug/batman_adv/bat0/originators)
batman_adv_gateway_mode=$(batctl gw)
batman_adv_gateway_list=$(awk \
'BEGIN { FS=" "; i=0 }
/B.A.T.M.A.N./ { next }
/Gateway/ { next }
/No gateways/ { next }
{ sub("\\(", "", $0)
sub("\\)", "", $0)
sub("\\[ *", "", $0)
sub("\\]:", "", $0)
sub("=> ", "true ", $0)
sub(" ", "false ", $0)
printf ""$1""$2""$3""$4""$5""$6" "$7" "$8""
i++
}' /sys/kernel/debug/batman_adv/bat0/gateways)
fi
err "$(date): Collecting information about conected clients"
#CLIENTS
client_count=0
dataclient=""
CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
for clientif in ${CLIENT_INTERFACES}; do
local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
client_count=$((client_count + cc))
dataclient="$dataclient<$clientif>$cc$clientif>"
done
dataair=""
w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
if [ -n "$w2dump" ] ; then
w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
dataair="$dataair$w2_ACT$w2_BUS"
fi
w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
if [ -n "$w5dump" ] ; then
w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
dataair="$dataair$w5_ACT$w5_BUS"
fi
err "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
DATA=""
DATA=$DATA"$SYSTEM_DATA"
DATA=$DATA"$interface_data"
DATA=$DATA"$BATMAN_ADV_INTERFACES"
DATA=$DATA"$batman_adv_originators"
DATA=$DATA"$batman_adv_gateway_mode"
DATA=$DATA"$batman_adv_gateway_list"
DATA=$DATA"$client_count"
DATA=$DATA"$dataclient"
DATA=$DATA"$dataair"
DATA=$DATA""
#write data to xml file that provides the data on httpd
SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
}
LANG=C
#Prüft ob das logfile zu groß geworden ist
err "$(date): Check logfile"
delete_log
#Erzeugt die statusdaten
err "$(date): Generate actual status data"
crawl
exit 0