You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
freshtomato-arm/release/src-rt-6.x.4708/router/others/discovery.sh

185 lines
4.9 KiB
Bash

#!/bin/sh
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/home/root
# Network discovery script v2.64 - ARM and MIPSR2 - 02/2025 - rs232
#------------------------------------------------------
# FreshTomato Network Discovery - usage
#
# arping = * scanning via arping (preferred)
# traceroute = scanning via traceroute
# nc = scanning via netcat
# all = all the above in round-robin
#
# lan = * only LANs interfaces
# wan = only WANs interfaces
# both = scan LANs and WANs
#
# clear = removes dirty records from the arp table post scan
#
# <5-200> = default 60, maximum number of concurrent scans
#------------------------------------------------------
script_name=$(basename "$0")
pid_file="/tmp/var/run/${script_name}.pid"
cleanup() {
rm -f "$pid_file"
exit 0
}
trap cleanup INT TERM EXIT
if [ -e "$pid_file" ]; then
pid_age=$(($(date +%s) - $(stat -c %Y "$pid_file")))
if [ "$pid_age" -gt 120 ]; then
echo "PID file is older than 2 minutes. Removing stale PID file."
rm -f "$pid_file"
fi
fi
debug=$(nvram get discovery_debug 2>/dev/null)
debug="${debug:-0}"
[ "$debug" -eq 1 ] && { echo "Debugging..."; date >> /tmp/discovery.debug; echo "$@" >> /tmp/discovery.debug; }
lim=$(echo "$@" | grep -oE '[0-9]+' | head -n 1 | awk '{if($1 < 5) print 5; else if($1 > 200) print 200; else print $1}')
[ -z "$lim" ] && lim=60
alias slp='usleep 250000'
alias low='nice -n 19'
tmp="/tmp/discovery.tmp"
scan=0
cl=0
runlan=0
runwan=0
fkill=0
iplist() {
input_cidr="$1"
cidr=$(echo "$input_cidr" | cut -d '/' -f 2)
ip=$(echo "$input_cidr" | cut -d '/' -f 1)
awk -v cidr="$cidr" -v ip="$ip" '
BEGIN {
split(ip, a, ".");
ip_int = a[1] * 256^3 + a[2] * 256^2 + a[3] * 256 + a[4];
num_addrs = 2^(32 - cidr);
base_ip = int(ip_int / num_addrs) * num_addrs;
for (i = 1; i < num_addrs - 1; i++) {
current_ip = base_ip + i;
printf "%d.%d.%d.%d\n",
int(current_ip / 256^3) % 256,
int(current_ip / 256^2) % 256,
int(current_ip / 256) % 256,
current_ip % 256;
}
}'
}
check_procs() {
case "$1" in
arping) pidof arping ;;
traceroute) pidof traceroute ;;
nc) pidof nc ;;
esac | wc -w
}
md5_param=$(echo "$@" | md5sum | cut -d' ' -f1)
if [ -f "$tmp" ]; then
if ! grep -q "$md5_param" "$tmp"; then
# Kill previous instances with different parameters
for PID in $(pidof "$script_name"); do
[ "$PID" != "$$" ] && kill -9 "$PID" &>/dev/null
done
# Kill scanning tools
for tool in arping traceroute nc; do
[ "$(check_procs "$tool")" -gt 0 ] && killall -q "$tool"
done
sleep 1
fkill=1
fi
else
echo 0 > "$tmp"
echo "$md5_param" >> "$tmp"
fi
for param in "$@"; do
case "$param" in
clear) cl=1 ;;
lan) runlan=1 ;;
wan) runlan=0; runwan=1 ;;
both) runlan=1; runwan=1 ;;
traceroute) scan=1 ;;
nc) scan=2 ;;
all) scan=$(head -1 "$tmp") ;;
esac
done
[ "$runlan" -eq 0 ] && [ "$runwan" -eq 0 ] && runlan=1
if [ -e "$pid_file" -a "$fkill" -ne 1 ]; then
echo "Status-devices - Background discovery processes already running; skipping this run." | tee /dev/tty | logger
cleanup
fi
scanthis() {
for iface in $this; do
cidr=$(ip a l dev "$iface" | grep inet | grep -v inet6 | awk '{print $2}')
[ "$(echo "$cidr" | cut -d/ -f2)" -lt 22 ] && {
echo "$iface - subnet mask shorter than /22. Too many IPs to scan - skipping..." | tee /dev/tty | logger
continue
}
[ "$(echo "$cidr" | cut -d/ -f2)" -lt 32 ] && {
ip=$(echo "$cidr" | cut -d/ -f1)
ipn=$(ip neigh show dev "$iface" | grep 'REACHABLE\|PERMANENT' | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
iplist "$cidr" | grep -vwE "$ip|$(echo "$ipn" | tr ' ' '\n')" | while read -r ip_addr; do
if [ "$scan" -eq 0 ]; then
while [ "$(check_procs arping)" -gt "$lim" ]; do slp; done
low arping -I "$iface" -q -c1 -w1 "$ip_addr" &>/dev/null &
elif [ "$scan" -eq 1 ]; then
while [ "$(check_procs traceroute)" -gt "$lim" ]; do slp; done
low traceroute -i "$iface" -r -F -m1 -q1 -s "$ip" "$ip_addr" &>/dev/null &
elif [ "$scan" -eq 2 ]; then
while [ "$(check_procs nc)" -gt "$lim" ]; do slp; done
low nc -w 1 "$ip_addr" &>/dev/null &
fi
done
wait
}
done
}
prune() {
ip n | grep -w "$1" | while read -r badip; do
ip=$(echo "$badip" | awk '{print $1}')
dev=$(echo "$badip" | awk '{print $3}')
ip neigh change "$ip" nud none dev "$dev"
done
}
echo $$ > "$pid_file"
[ "$runlan" -eq 1 ] && {
this=$(brctl show | grep -Eo ^br[0-9])
scanthis
}
unset wans
[ "$runwan" -eq 1 ] && {
[ "$(ip rule | grep -Eo 'WAN[1-4]' | sort -u | wc -l)" -gt 0 ] && {
for WAN in $(ip rule | grep -Eo 'WAN[1-4]' | sort -u); do
wans="$wans $(ip r l t "$WAN" | grep default | grep -Eo '[vlan|eth]+[0-9]{1,4}')"
done
} || {
wans=$(ip route | grep ^default | awk '{print $5}')
}
this="$wans"
scanthis
}
[ "$cl" -eq 1 ] && {
prune "FAILED\|INCOMPLETE"
usleep $((lim * 30000))
prune "STALE\|DELAY\|PROBE"
}
scan=$(((${scan:-0} + 1) % 3))
{
echo "$scan"
echo "$md5_param"
} >> "$tmp"
cleanup