Home > Net >  Trying to get BASH backup script to find an IP address based off known MAC address?
Trying to get BASH backup script to find an IP address based off known MAC address?

Time:05-05

I have a small BASH backup script that uses Rsync to grab a handful of computers on my LAN. It works very well for static devices using an Ethernet cable - trouble comes in for my even smaller number of Laptop users that have docks. Every once in a while they do not connect to the Dock & Ethernet cable/statically assigned address and end up on the WiFi with a DHCP assigned address. I already have a list of known statically assigned targets in a file that is parsed through to actually backed up. So I keep thinking I should fairly easily be able to create a second file with an nmap scan before each backup run with other code I found - something like:

    sudo nmap -n -sP 192.168.2.0/24 | awk '/Nmap scan report for/{printf $5;}/MAC Address:/{print " => "$3;}' | sort

which gives me a list of 192.168.2.101 => B4:FB:E4:FE:C6:6F for all found devices in the LAN. I just removed the | sort and send it to a file > found.devices instead.

So Now I have a list of found devices IP and MAC address - and I'd like to compare the two files and create a new target list with any changed IP addresses found (for those Laptop users that forgot to connect to the Dock and are now using DHCP). But I still want to keep my original targets file clean for the times that they do remember and also continue to get those other devices that are wired all the time while ignoring everything else on the LAN.

found.devices
192.168.2.190 => D4:XB:E4:FE:C6:6F
192.168.2.102 => B4:QB:Y4:FE:C6:6F
192.168.2.200 => B4:FB:P4:ZE:C6:6F
192.168.2.104 => B4:FB:E4:BE:P6:6F

known.targets
192.168.2.101 D4:XB:E4:FE:C6:6F domain source destination 
192.168.2.102 B4:QB:Y4:FE:C6:6F domain source destination 
192.168.2.103 B4:FB:P4:ZE:C6:6F domain source destination 
192.168.2.104 B4:FB:E4:BE:P6:6F domain source destination 

Should get a list or a file for the current back run to use of:
192.168.2.190 domain source destination
192.168.2.102 domain source destination
192.168.2.200 domain source destination
192.168.2.104 domain source destination

Currently my bash script just reads the file of known.targets one line at a time:

cat /known.targets | while read ip hostname source destination
     do 
     this mounts and backs up the data I want ... 

I really like the current system, and have found it to be very reliable for my simple needs, just need to find some way to get those users that intermittently forget to dock. I expect its series of nested loops, but I cannot get my head to wrap around it - been away from actual coding for too long - Any suggestions would be greatly appreciated. I'd also really like to get rid of the => and just use comma or space separated data but every time I mess with that awk statement - I end up shifting the data and getting an oddly placed CR somewhere I cannot figure it either!

CodePudding user response:

UPDATE: per comment from OP, dropping assumption (and associated code) about keeping an IP address that shows up in found.devices but without a match in known.targets (ie, this cannot happen)


Assumptions:

  • start with a list of IP/MAC addresses from known.targets
  • if a MAC address also shows up in found.devices then the IP address from found.devices takes precendence

Adding a standalone entry to both files:

$ cat known.targets
192.168.2.101 D4:XB:E4:FE:C6:6F domain source destination
192.168.2.102 B4:QB:Y4:FE:C6:6F domain source destination
192.168.2.103 B4:FB:P4:ZE:C6:6F domain source destination
192.168.2.104 B4:FB:E4:BE:P6:6F domain source destination
111.111.111.111 AA:BB:CC:DD:EE:FF domain source destination

$ cat found.devices
192.168.2.190 => D4:XB:E4:FE:C6:6F
192.168.2.102 => B4:QB:Y4:FE:C6:6F
192.168.2.200 => B4:FB:P4:ZE:C6:6F
192.168.2.104 => B4:FB:E4:BE:P6:6F
222.222.222.222 => FF:EE:CC:BB:AA:11

One awk idea:

$ cat ip.awk
FNR==NR  { ip[$2]=$1; dsd[$2]=$3 FS $4 FS $5; next }
$3 in ip { ip[$3]=$1 }
END      { for (mac in ip) print ip[mac],dsd[mac] }

Running against our files:

$ awk -f ip.awk known.targets found.devices
192.168.2.200 domain source destination
192.168.2.190 domain source destination
192.168.2.104 domain source destination
111.111.111.111 domain source destination
192.168.2.102 domain source destination

Feeding this to a while loop:

while read ip hostname source destination
do
    echo "${ip} : ${hostname} : ${source} : ${destination}"
done < <(awk -f ip.awk known.targets found.devices)

This generates:

192.168.2.200 : domain : source : destination
192.168.2.190 : domain : source : destination
192.168.2.104 : domain : source : destination
111.111.111.111 : domain : source : destination
192.168.2.102 : domain : source : destination

CodePudding user response:

If join is an option:

join -1 3 -2 2 <(sort -k 3 found.devices) <(sort -k 2 known.targets) -o 1.1,2.3,2.4,2.5

Output:

192.168.2.104 domain source destination
192.168.2.200 domain source destination
192.168.2.102 domain source destination
192.168.2.190 domain source destination

CodePudding user response:

Try this pure Bash code:

declare -A found_mac2ip
while read -r ip _ mac; do
    [[ -n $mac ]] && found_mac2ip[$mac]=$ip
done <'found.devices'

while read -r ip mac domain source destination; do
    ip=${found_mac2ip[$mac]-$ip}
    # ... DO BACKUP FOR $ip ...
done <'known.targets'
  • It first sets up a Bash associative array mapping found mac address to ip addresses.
  • It then loops through the known.targets file and for each mac address it uses the ip address from the known.targets file if the mac address is listed in it. Otherwise it uses the ip address read from the known.targets file.

It's also possible to extract the "found" MAC and IP address information by getting it directly from the nmap output instead of from a `found.devices' file. This alternative version of the code does that:

declare -A found_mac2ip
nmap_output=$(sudo nmap -n -sP 192.168.2.0/24)
while IFS=$' \t\n()' read -r f1 f2 f3 f4 f5 _; do
    [[ "$f1 $f2 $f3 $f4" == 'Nmap scan report for' ]] && ip=$f5
    [[ "$f1 $f2" == 'MAC Address:' ]] && found_mac2ip[$f3]=$ip
done <<<"$nmap_output"

while read -r ip mac domain source destination; do
    ip=${found_mac2ip[$mac]-$ip}
    # ... DO BACKUP FOR $ip ...
done <'known.targets'
  • Related