#!/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"" 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" 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" 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