2023-03-02 18:38:35 +08:00

210 lines
5.8 KiB
Bash
Executable File

#!/bin/sh
lookup() {
local MAC=$1
local IP=$2
local USERSFILE
local USER
for USERSFILE in /tmp/dhcp.leases /tmp/hosts /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do
[ -e "$USERSFILE" ] || continue
case $USERSFILE in
/tmp/dhcp.leases)
USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ')
;;
/etc/hosts)
USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ')
;;
/tmp/hosts)
USER=$(grep -rhm1 "^$IP " $USERSFILE | head -1 | cut -f2 -s -d' ')
;;
*)
USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,)
;;
esac
[ "$USER" = "*" ] && USER=
[ -n "$USER" ] && break
done
[ -z "$USER" ] && return 1
echo $USER
}
get_wan_iface() {
tail -n +2 /proc/net/route | sed -n -e 's/^\([^\t]\+\)\t00000000\t[^\t]\+\t[^\t]\+\t[^\t]\+\t[^\t]\+\t[^\t]\+\t00000000\t.*$/\1/p'
}
get_arp_excluded() {
tail -n +2 /proc/net/arp | grep -v " ${1//\./\\\.}\$" | sed -n -e 's/^\([^ ]\+\) \+0x[^ ]\+ \+0x2 \+\([^ ]\+\) .* \([^ ]\+\)$/\1\t\2\t\3/p'
}
merge() {
local arpfile="$1"
local countfile="$2"
local outfile="$3"
local pkts bytes src dest ip mac iface up down
while read pkts bytes src dest; do
if [[ "$dest" = '0.0.0.0/0' ]]; then
eval "local up_${src//[.:]/_}=\"$pkts,$bytes\""
else
eval "local down_${dest//[.:]/_}=\"$pkts,$bytes\""
fi
done < "$countfile"
while read ip mac iface; do
eval "up=\$up_${ip//[.:]/_}"
eval "down=\$down_${ip//[.:]/_}"
printf "%s,%s,%s,%s,%s,%s\n" "$ip" "$mac" "$iface" "${up:-0,0}" "${down:-0,0}" "`lookup $mac $ip`"
done < "$arpfile" > "$outfile"
}
do_clean() {
iptables -t mangle -D FORWARD -j RTBWMON_IFACE 2>/dev/null
iptables -t mangle -F RTBWMON_IFACE 2>/dev/null
iptables -t mangle -F RTBWMON_IP 2>/dev/null
iptables -t mangle -X RTBWMON_IFACE 2>/dev/null
iptables -t mangle -X RTBWMON_IP 2>/dev/null
rm -f /var/run/rtbwmon.tmp.* /var/run/rtbwmon.csv
}
do_update() {
local ip
local INTERFACE="$1"
find /var/run/rtbwmon.csv -mmin +30 2>/dev/null | grep -q . && do_clean
# init iptable
iptables -t mangle -C FORWARD -j RTBWMON_IFACE 2>/dev/null || {
iptables -t mangle -N RTBWMON_IFACE 2>/dev/null
iptables -t mangle -N RTBWMON_IP 2>/dev/null
iptables -t mangle -I FORWARD -j RTBWMON_IFACE
# iptables -t mangle -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j RTBWMON_IFACE
}
# if interface changed, clean chain
iptables -t mangle -C RTBWMON_IFACE -o "$INTERFACE" -j RTBWMON_IP 2>/dev/null || {
iptables -t mangle -F RTBWMON_IP
iptables -t mangle -F RTBWMON_IFACE
# iptables -t mangle -A RTBWMON_IFACE -m addrtype --dst-type LOCAL -j RETURN
iptables -t mangle -A RTBWMON_IFACE -i "$INTERFACE" -j RTBWMON_IP
iptables -t mangle -A RTBWMON_IFACE -o "$INTERFACE" -j RTBWMON_IP
}
# schedule cleaning task
/etc/init.d/rtbwmon start
# save system state
iptables -t mangle -nvxL RTBWMON_IP | tail -n +3 | grep -Fv 'Zeroing chain' | sed -e 's/ \+/\t/g' | cut -f2,3,9,10 >/var/run/rtbwmon.tmp.count
get_arp_excluded "$INTERFACE" >/var/run/rtbwmon.tmp.arp
# get ip
cut -f3 /var/run/rtbwmon.tmp.count | grep -Fv '0.0.0.0/0' >/var/run/rtbwmon.tmp.oips
cut -f1 /var/run/rtbwmon.tmp.arp >/var/run/rtbwmon.tmp.nips
# delete offline ip
grep -Fvf /var/run/rtbwmon.tmp.nips /var/run/rtbwmon.tmp.oips | while read ip; do
iptables -t mangle -D RTBWMON_IP -s "$ip" -j RETURN
iptables -t mangle -D RTBWMON_IP -d "$ip" -j RETURN
done
# add new ip
grep -Fvf /var/run/rtbwmon.tmp.oips /var/run/rtbwmon.tmp.nips | while read ip; do
iptables -t mangle -A RTBWMON_IP -s "$ip" -j RETURN
iptables -t mangle -A RTBWMON_IP -d "$ip" -j RETURN
done
merge /var/run/rtbwmon.tmp.arp /var/run/rtbwmon.tmp.count /var/run/rtbwmon.csv
rm -f /var/run/rtbwmon.tmp.*
return 0
}
update() {
local WAN_INTERFACE=`get_wan_iface`
exec 1000>/var/run/rtbwmon.lock
flock -n 1000 2>/dev/null || {
flock 1000 2>/dev/null
[ -f /var/run/rtbwmon.csv ] && cat /var/run/rtbwmon.csv
flock -u 1000 2>/dev/null
return 1
}
if [ -z "$WAN_INTERFACE" ]; then
do_clean
else
do_update "$WAN_INTERFACE" 2>/dev/null
cat /var/run/rtbwmon.csv
fi
flock -u 1000 2>/dev/null
return 0
}
clean() {
exec 1000>/var/run/rtbwmon.lock
flock 1000
do_clean
flock -u 1000
}
run_gc() {
local pid
exec 1001>/var/run/rtbwmon_gc.lock
flock -n 1001 2>/dev/null || return 0
while :; do
sleep 360 </dev/null >/dev/null 2>&1 1000>/dev/null 1001>/dev/null &
pid=$!
trap "kill $pid;trap TERM;kill -TERM $$" TERM
wait $pid
trap TERM
if ! find /var/run/rtbwmon.csv -mmin -5 2>/dev/null | grep -q .; then
break
fi
done
[ -f /var/run/rtbwmon.csv ] && clean
flock -u 1001
return 0
}
show_ifaces() {
local WAN_INTERFACE=`get_wan_iface`
[ -z "$WAN_INTERFACE" ] && return 1
ip addr show scope global up | grep '^ \+inet ' | sed -n -e 's/^.* \([^ ]\+\)$/\1/p' | grep -Fv "$WAN_INTERFACE" | sort -u
}
prerm() {
# avoid invoke
chmod 644 /usr/libexec/rtbwmon.sh
exec 1000>/var/run/rtbwmon.lock
flock 1000
sleep 1 </dev/null >/dev/null 2>&1 1000>/dev/null
do_clean
flock -u 1000
}
case $1 in
"clean")
clean
;;
"update")
update
;;
"ifaces")
show_ifaces
;;
"gc")
run_gc
;;
"prerm")
prerm
;;
*)
echo \
"Usage: $0 {update|clean|ifaces}
Actions:
update update and get
clean clean iptables and temp files
ifaces show up interfaces
"
;;
esac