Makefile evaluate 2 variables then use the non-empty one - makefile

I have a TV box running CoreELEC (a Linux distro similar to LibreELEC) and I would like to find its IP address to then use SSH to log into it.
I know the MAC addresses of both the Ethernet interface and the Wifi interface.
I want to find the IP address of my TV box in my LAN (either Ethernet or Wifi) assuming I don't know which interface is currently used by the TV box to connect to the LAN.
The following list of targets does not work as it fails when evaluating the "OR":
TVBOX_IP=""
find-tvbox-eth-ip:
#echo Checking the Ethernet IP address...
$(eval TVBOX_ETH_IP=$(shell sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_ETH_MAC) | awk '{print $$1}'))
#echo Found an Ethernet IP address: "$(TVBOX_ETH_IP)"
find-tvbox-wifi-ip:
#echo Checking the Wifi IP address...
$(eval TVBOX_WIFI_IP=$(shell sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_WLAN_MAC) | awk '{print $$1}'))
#echo Found a Wifi IP address: "$(TVBOX_WIFI_IP)"
find-tvbox-ip: find-tvbox-eth-ip find-tvbox-wifi-ip
#[ "$(TVBOX_ETH_IP)" ] && TVBOX_IP:=$(TVBOX_ETH_IP) || ( echo TVBOX_IP:=$(TVBOX_WIFI_IP) )
#echo "Stored this IP for the TV BOX: " $(TVBOX_IP)
A similar target containing TVBOX_IP := $(or $(TVBOX_ETH_IP),$(TVBOX_WIFI_IP)) does not work as well.
How can I use the variable $(TVBOX_IP) in other targets after making sure their value come first from the Ethernet check, then from the Wifi check?
What's wrong with the Makefile targets above?

Sometimes, it is easier to move logic to external commands. Make declarative approach is sometimes hard to control:
Consider the alternative: Moving the conditional to the shell.
# Notice this is definition, will not force immediate evaluation
TVBOX_ETH_IP= sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_ETH_MAC) | awk '{print $$1}'
TVBOX_WIFI_IP=sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_WLAN_MAC) | awk '{print $$1}'
find-tvbox-ip:
IP=$$(${TVBOX_ETH_IP}) ; [ "$$IP" ] || IP=$$(${TVBOX_WIFI_IP}) ; echo "IP=$$IP"
Or keeping the condition in make $(or ...)
TVBOX_ETH_IP=$(shell sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_ETH_MAC) | awk '{print $$1}')
TVBOX_WIFI_IP=$(shell sudo arp-scan 192.168.0.1/24 2>&1 | grep $(TV_WLAN_MAC) | awk '{print $$1})'
TVBOX_IP=$(or ${TVBOX_ETH_IP}, ${TVBOX_ETH_IP})
find-tvbox-ip:
IP=${TVBOX_IP} ; echo "IP=$$IP"

Related

Shell Script IP Neighbor Refresh

I am working on an application of multiple devices in the same network. One of them takes the lead and performs some functions. I arbitrate the "lead" by the highest IP I find.
My application is intended to be fault-tolerant and if I loose the controller, next in the line should take over.
I am running the script below.
#define SHELLSCRIPT "\
#/bin/bash \n\
echo $(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1) > IP.txt\n\
while read LINE; do echo $LINE | grep -i -E 192.168 | grep -v .254 | cut -c1-13; done < /proc/net/arp >> IP.txt\n\
"
The problem I have found is that the ARP cache does not refresh automatically. Does anyone has any idea how to "refresh" the ARP table (without using arp commands).
I have already tried "ip -s neigh flush all", but it seems to have a delay to refresh the ARP table.
Anyway, I would appreciate any suggestion.
You can disable and enable the use of the ARP protocol on interface at the same time.
ARP cache will be cleared quitly fast.
ip link set arp off dev eth0 ; ip link set arp on dev eth0
Please, at first run this on test environment for checking and be sure there no connection interruption.

Processing ifconfig and hostname output and frame it in single line for multiple hosts

I'm trying to filter remote machine mac address , IP and hostname from 100 machines. Initially I'm capturing the information using below command.
$for i in `cat IP`;do in ssh root#$IP "ifconfig eth0 && hostname " ;done
eth0 Link encap:Ethernet HWaddr 00:MN:77:TR:XX:ZZ
inet addr:192.168.122.25 Bcast:192.168.122.255
Mask:255.255.224.0
test.com-112304
eth0 Link encap:Ethernet HWaddr 00:TT:77:MM:XX:YY
inet addr:192.168.122.22 Bcast:192.168.122.255
Mask:255.255.224.0
test.com-11035
Initially the output redirect to one file. from their I need to process output which comes in the above format.
I can able to accomplish to print IP and mac by line as follows
$cat input | awk '/HWaddr/{printf $NF;printf " ";getline;print $2;}' | cut -c1-18,24-
00:MN:77:TR:XX:ZZ 192.168.122.25
00:TT:77:MM:XX:YY 192.168.122.22
Actually I want to include hostname along with the output as follows
00:MN:77:TR:XX:ZZ 192.168.122.25 test.com-112304
00:TT:77:MM:XX:YY 192.168.122.22 test.com-11035
test.com will be common name for all hostname. I tried redirect both output in two variable and called as follows , but no luck.
a=`cat input | awk '/HWaddr/{printf $NF;printf " ";getline;print $2;}' | cut -c1-18,24-`
b=`grep test.com input`
echo $a $b | xargs -n2
Please shed some views
I'm trying to filter remote machine mac address , IP and hostname from 100 machines.
Machine mac address, from here: cat /sys/class/net/eth0/address
You have hostname utility, why don't you just hostname -i? You can parse ifconfig | grep inet | awk '{print $2}' | sed 's/addr://' and hope ifconfig versions are the same across all machines (some ifconfig verions return inet <ip> some return inet addr:<ip> like yours).
Hostname with hostname
Putting together:
echo $(cat /sys/class/net/eth0/address) $(ifconfig eth0 | grep inet | awk '{print $2}') $(hostname)
Executing a command for each line in some file is a job for xargs and remember about properly escaping your arguments:
cat IP | xargs -n1 -I{} ssh root#{} 'echo $(cat /sys/class/net/eth0/address) $(ifconfig eth0 | grep inet | awk '\''{print $2}'\'' | sed '\''s/addr://'\'') $(hostname)'
If you really have 100 machines, ansible might interest you.
If you really have that "input" file and you can't change it, you may parse it like this:
sed 's/eth0/#eth0/' input \
| xargs -d'#' -n1 -- bash -c '{ echo "$1" | grep HWaddr | awk "{print \$5}"; echo "$1" | grep inet | awk "{print \$2}" | sed "s/addr://"; echo "$1" | grep "^test.com"; } | tr "\n" " "; echo' --
And this hurts my eyes:
for i in `cat IP`; then

Bash grep file for string and use each as a variable in another commands

In HA configuration I am checking periodically for VIP address on eth0, (lets call it 2.2.2.2). If it is up, then I need to bring up another group of IP address defined for eth0 in /etc/network/interfaces configuration file:
up ip addr add **1.2.3.34** dev $IFACE
up ip addr add **1.2.3.40** dev $IFACE
up ip addr add **1.2.3.48** dev $IFACE
and pass each IP only to another group of commands:
ip a a **1.2.3.34/32** dev eth0
ip a a **1.2.3.40/32** dev eth0
ip a a **1.2.3.48/32** dev eth0
What I've done so far is:
#!/bin/bash
STATUS=$(ip a s eth0 | grep inet | awk '{print $2}' | sed 's/addr://')
if ip a s eth0 | grep inet | awk '{print $2}' | sed 's/addr://' | grep 2.2.2.2/27 ; then
cat /etc/network/interfaces | grep -o "up ip addr add [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | grep -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" > /tmp/ext_ip.txt
Now I need help how to pass each line to another command mentioned above (ip a a 1.2.3...), but have no idea how to do this properly.
Optionally I'd like to revert operation if VIP is not present in the system - in case if primary HA host will go offline.
One way to achieve this would be to parse all IP addresses into an array and use a for loop to assign them to the interface:
#!/bin/bash
IFACE='eth0'
VIP='192.168.0.1'
IFACES_FILE='/etc/network/interfaces'
STATUS=$( ip address show "$IFACE" | grep -o "$VIP" )
if [ ! -z "$STATUS" ]; then
ip_addresses=( $( grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' "$IFACES_FILE" ) )
for ip in "${ip_addresses[#]}"; do
ip address add "$ip" dev "$IFACE"
done
fi
This is a simplified example. You may want to add more checks, add some logging messages to provide output useful for debugging. Also, depending on your server configuration some commands may not work without sudo.
Thanks Andrii L. I've improved your solution to:
#!/bin/bash
IFACE='eth0'
VIP='2.2.2.2'
IFACES_FILE='/etc/network/interfaces'
STATUS=$( ip address show "$IFACE" | grep -o "$VIP" )
if [ ! -z "$STATUS" ]; then
ip_addresses=( $( grep -o 'up ip addr add [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' "$IFACES_FILE" | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' ) )
for ip in "${ip_addresses[#]}"; do
ip address add "$ip"/32 dev "$IFACE"
done
else
for ip in "${ip_addresses[#]}"; do
ip address del "$ip"/32 dev "$IFACE"
done
fi
otherwise it is trying to add all IPs and broadcasts found in /etc/network/interfaces file.

tcpdump: Output only source and destination addresses

Problem description:
I want to print only the source and destination address from a tcpdump[1].
Have one working solution, but believe it could be improved a lot. An example that captures 5 packets, just as an example of what I'm looking for:
tcpdump -i eth1 -n -c 5 ip | \
cut -d" " -f3,5 | \
sed -e 's/^\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\..* \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*$/\1 > \2/'
Question:
Can this be done in any easier way? Performance is also an issue here.
[1] A part of a test if the snort home_net is correctly defined, or if we see traffic not defined in the home_net.
Solution:
Ok, thanks to everyone who have replied to this one. There have been two concerns related to the answers, one is the compatibility across different linux-versions and the second one is speed.
Here is the results on the speed test I did. First the grep-version:
time tcpdump -l -r test.dmp -n ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo >/dev/null
real 0m5.625s
user 0m0.513s
sys 0m4.305s
Then the sed-version:
time tcpdump -n -r test.dmp ip | sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)
real 0m0.491s
user 0m0.496s
sys 0m0.020s
And the fastest one, the awk-version:
time tcpdump -l -r test.dmp -n ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)
real 0m0.093s
user 0m0.111s
sys 0m0.013s
Unfortunately I have not been able to test how compatible they are, but the awk needs gnu awk to work due to the gensub function. Anyway, all three solutions works on the two platforms I have tested them on. :)
Here's one way using GNU awk:
tcpdump -i eth1 -n -c 5 ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }'
Try this:
tcpdump -i eth1 -n -c 5 ip 2>/dev/null | sed -r 's/.* ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).* > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1 > \2/'
If running from a .sh script, remember to escape \1 & \2 as required.
Warning You have to use unbuffered ou line-buffered output to monitor the output of another command like tcpdump.
But you command seem correct.
To simplify, you could:
tcpdump -i eth1 -n -c 5 ip |
sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'
Notice the u switch usefull without -c 5 at tcpdump
tcpdump -ni eth1 ip |
sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'
& here is a grep only solution:
tcpdump -l -i eth1 -n -c 5 ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo
Note -l, in case you don't want to limit the number of packets using -c.

Linux/Bash ARP Lookups

Very simply I am looking to get a list of all devices on a specific subnet for the purpose of identifying their mac address to find all devices by a particular vendor on that network.
Presently I am using nmap to accomplish this, however it makes me specify a host, example 10.0.0.0/24, which is good for 10.0.0.0 addresses, however I would like to be able to get the 10.0.1.0 devices and 10.1.1.0 devices as well.
Any ideas?
try this:
nmap -TAggressive -n -sS -p80 10.0.0.0/24 &>/dev/null
nmap -TAggressive -n -sS -p80 10.0.1.0/24 &>/dev/null
nmap -TAggressive -n -sS -p80 10.1.1.0/24 &>/dev/null
arp -an | awk 'BEGIN {print "MAC IP"}{++i;print $4, $2} END { print i,"hosts found"}' | tr -d '()'

Resources