Shell Script IP Neighbor Refresh - shell

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.

Related

Cron job creates empty files

I want to preface that I am a newbie that picked up shell scripting 2 weeks ago.
Hey guys I need help with something, hope someone can point me in the right direction. I have a script that works when I run it from the command line but every time I run it with a crontab, the output is a few empty files. Does anyone know why?
That's the code down there
#!/bin/bash
#Provide an IP address as an argument to use nmap
#make sure to add the full range with (0-225 or 0/24) at the end
IPADDRESS=$(hostname -I | awk '{print $1}')
network-scan(){
if [ $1 ]
then
sudo nmap -sn $1
else
sudo nmap -sn 192.168.1.0-255
fi
}
#Scan the whole network and only prints the IP addresses minus your own
#Sends the IP addresses to a file
network-scan | grep -i 'Nmap scan report' | \
sed 's/\ /\n/g'|sed 's/(//g'|sed 's/)//g' | \
grep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | grep -v ${IPADDRESS} > ip_addresses
#Scan the whole network and only prints the MAC addresses
#Sends the MAC addresses to a file
network-scan | grep -i 'MAC Address:' | \
awk '{print $3}' > mac_addresses
#Put the IP and MAC addresses in the same file
paste ip_addresses mac_addresses | \
column -s $'\t' -t > "scan_$(date +%d-%m-%Y_%H:%M:%S)"
#Notify that a file with the IP and MAC addresses has been created on the Desktop
echo "A file containing the results of the scan has been created on the Desktop"
exit 0
You are using
network-scan | grep
without passing any parameter.
Hence network-scan function always using
sudo nmap -sn 192.168.1.0-255
when you run it from command line are you passing any parameter ?
echo $IPADDRESS inside the script when executing at cron and at command line for debugging.
network-scan | grep -i 'Nmap scan report' | \
sed 's/\ /\n/g'|sed 's/(//g'|sed 's/)//g' | \
grep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | grep -v ${IPADDRESS}
Since you are obtaining empty output, validate each command and append(test) each OR operators to know where it is removing required output.

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.

use tcpkill command from an ip list

I have got an ip list in a file called ips:
ip1
ip2
I want to tcpkill from this list. I cannot do it from tcpkill command options. I need a script which will write :
tcpkill -i eth0 -9 host ip1 or host ip2
the list can grow in time.
the only thing I know is that I will need a loop to read the list:
for IP in $(cat list) ; do
echo "tcpkill -i eth0 -9 host $IP " (for
the first element of the list)
echo "or host $IP" (for the rest of
the list).
So my questions are:
1. what would be the right syntax for this purpose?
2. Is there a completely different way of doing this?
Any idea folks ?!
thank you very much.
This single line command would append the IP list to tcpkill command to form the complete command:
tcpkill -i eth0 -9 host $(cat list | xargs | sed 's/ / or host /g')
You can put this command after echo to see how the command gets formed.
echo tcpkill -i eth0 -9 host $(cat list | xargs | sed 's/ / or host /g')

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