Skip to content

Instantly share code, notes, and snippets.

@Qhilm
Forked from mimugmail/opn-arp.sh
Last active December 3, 2024 14:50
Show Gist options
  • Save Qhilm/6d5b76732bef21c7a2838b678f5f0665 to your computer and use it in GitHub Desktop.
Save Qhilm/6d5b76732bef21c7a2838b678f5f0665 to your computer and use it in GitHub Desktop.
opn-arp.sh
#!/usr/local/bin/bash
# This file is located under /usr/local/bin/opn-arp.sh
# Source configuration file
. /usr/local/etc/opn-arp.conf # This file defines:
# - interfaces to be used
# - dhcpv6_range_start
# - dhcpv6_range_stop
# Define file paths for IPv4 and IPv6 ARP/NDP tables
CURRENT4="/tmp/current_arp_table4.txt"
STATIC4="/tmp/static_arp_table4.txt"
OUT4="/tmp/result_arp_table4.txt"
CURRENT6="/tmp/current_arp_table6.txt"
STATIC6="/tmp/static_arp_table6.txt"
OUT6="/tmp/result_arp_table6.txt"
# Ensure all necessary files exist
touch $CURRENT4 $STATIC4 $OUT4 $CURRENT6 $STATIC6 $OUT6
# Function to normalize IPv6 address
normalize_ipv6() {
local ip=$1
# Remove interface name if present
ip=${ip%\%*}
# Expand :: to appropriate number of :0:
if [[ $ip == *::* ]]; then
local colons=${ip//[^:]};
local missing=$((8 - ${#colons}))
local replacement=$(printf ':0%.0s' $(seq 1 $missing))
ip=${ip/::/$replacement:}
fi
# Add leading zeros to each group
ip=$(echo $ip | awk -F: '{for(i=1;i<=NF;i++) printf "%04x:", substr("0000" $i, length($i)+1)}' | sed 's/:$//')
echo $ip
}
# Function to compare two IPv6 addresses
compare_ipv6() {
local a=$(normalize_ipv6 $1)
local b=$(normalize_ipv6 $2)
if [[ $a < $b ]]; then
echo -1
elif [[ $a > $b ]]; then
echo 1
else
echo 0
fi
}
# Function to check if an IPv6 address is in the specified range
is_ipv6_in_range() {
local ip=$1
local start=$2
local stop=$3
# Check if it's a link-local address (starts with fe80)
if [[ $ip == fe80::* ]]; then
return 0 # Always include link-local addresses
fi
# Check if it's a ULA address (starts with fd)
if [[ $ip == fd* ]]; then
return 0 # Always include ULA addresses
fi
local cmp_start=$(compare_ipv6 "$ip" "$start")
local cmp_stop=$(compare_ipv6 "$ip" "$stop")
[ $cmp_start -ge 0 ] && [ $cmp_stop -le 0 ]
}
# Main loop
while true
do
# Clear previous content
> "$CURRENT4"
> "$CURRENT6"
if [ -z "$interfaces" ]
then
# If no specific interfaces are defined, check all
arp -an | grep -v 'incomplete' | grep -v 'permanent' | awk '{print $2 " | " $4}' > "$CURRENT4"
ndp -an | grep -v 'incomplete' | grep -v 'permanent' | grep -v 'Neighbor' | awk '{print $1 " | " $2}' | while read -r line; do
ip=$(echo "$line" | cut -d '|' -f1 | tr -d ' ')
if [ -z "$dhcpv6_range_start" ] || [ -z "$dhcpv6_range_stop" ] || is_ipv6_in_range "$ip" "$dhcpv6_range_start" "$dhcpv6_range_stop"; then
echo "$line" >> "$CURRENT6"
fi
done
echo "Processed all interfaces"
else
# If specific interfaces are defined, check only those
for a in $interfaces
do
echo "Processing interface: $a"
arp -an | grep -v 'incomplete' | grep -v 'permanent' | grep "$a" | awk '{print $2 " | " $4}' >> "$CURRENT4"
ndp -an | grep -v 'incomplete' | grep -v 'permanent' | grep -v 'Neighbor' | grep "$a" | awk '{print $1 " | " $2}' | while read -r line; do
ip=$(echo "$line" | cut -d '|' -f1 | tr -d ' ')
if [ -z "$dhcpv6_range_start" ] || [ -z "$dhcpv6_range_stop" ] || is_ipv6_in_range "$ip" "$dhcpv6_range_start" "$dhcpv6_range_stop"; then
echo "$line" >> "$CURRENT6"
fi
done
done
fi
# Compare current and static tables, output new entries
comm -2 -3 <(sort -u "$CURRENT4") <(sort -u "$STATIC4") > "$OUT4"
comm -2 -3 <(sort -u "$CURRENT6") <(sort -u "$STATIC6") > "$OUT6"
# Log and add new IPv4 entries
while read -r line; do
logger -p daemon.notice "New IPv4/MAC pair seen: $line"
echo "$line" >> "$STATIC4"
done < "$OUT4"
# Log and add new IPv6 entries
while read -r line; do
logger -p daemon.notice "New IPv6/MAC pair seen: $line"
echo "$line" >> "$STATIC6"
done < "$OUT6"
# Sort and remove duplicates from static tables
sort -u -o "$STATIC4" "$STATIC4"
sort -u -o "$STATIC6" "$STATIC6"
# Wait before next iteration
sleep 5
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment