How to execute nmap from ping script - bash

I'm learning bash for pentesting, so i started with kinda usefull things for me. I created a script, thath scan whole network by my requirements. But at the end of script i want to do Nmap of this Ips.
And thats the problem, no idea how to execute it.
time=$(date +"%T")
ip=(192.168.0)
echo -e "Scan started at $time"
for x in $(seq 1 254); do
ping -c 1 $ip.$x | grep "from" &
done
echo -n "Would you like to do NMAP scan (y/n)? "
read nmap
if [ "$nmap" != "${nmap#[Yy]}" ] ;then
#here i guess have to be something
else
#here i guess have to be something
fi
If user chose "y" than NMAP should scan IPs, which are pinged as live.

Here is a simple solution on how to use ping and nmap together
#!/bin/bash
ipfile=$(mktemp) # create tmpfile for online ip's
trap 'rm -f "$ipfile"' EXIT # rm tmpfile on exit
BASE="192.168.0" # define your IP base
for (( i=1; i <= 254; i++ )); do
ip="$BASE.$i"
printf "Scanning %s " "$ip"
# check if ip is online
if ping -c 1 "$ip" | grep "from" >/dev/null; then
printf "online\n"
# write ip's into tmpfile
printf "%s\n" "$ip" >> "$ipfile"
else
printf "offline\n"
fi
done
echo -n "Would you like to do NMAP scan (y/n)? "
read -r answer
if [ "$answer" = "y" ]; then
# check all ip's in tmpfile with nmap
nmap -iL "$ipfile"
fi

Related

How to awk all lines instead of only looking at the first

I'm trying to write a script that allows you to enter your machine name, and then lets you know if the host is on the local network. Here's what I have:
#!/bin/bash
echo "Please enter the host you would like to ping:"
read -r host
output=$(ruptime | awk '{print $1}')
if [ "$output" == "$host" ];
then
echo "$host is up"
else
echo "$host is down"
fi
This works when I enter my machine name 'ubuntu' since I am the only one on my LAN and the awk statement outputs 'ubuntu'.
If I run for example:
#!/bin/bash
echo "Please enter the host you would like to ping:"
read -r host
output=$(cat /etc/hosts | awk '{print $1}')
if [ "$output" == "$host" ];
then
echo "$host is up"
else
echo "$host is down"
fi
The output is 2 lines: localhost and ubuntu. If I then run the script and enter either one of those, it says it's not found.
I think the awk is only looking for the value in the first line. How can I have the script check every line from the output of the awk and then compare it to what was entered?
Thanks in advance!
You're setting $output to all the names. You're not checking if $host is one of them, you're checking if $host is equal to all of them at once.
grep is a better way to do this.
if ruptime | grep -q -w "$host"
then echo "$host is up"
else echo "$host is down"
fi
Assuming that your goal is to look at whether a given name is in the first column of the output from ruptime, that might look like:
#!/usr/bin/env bash
hostname="target"
while read -r hostname _; do
[[ $hostname = "$target" ]] && { echo "$target is up"; break; }
done < <(ruptime)
read -r hostname _ puts only the first column of each line into hostname, putting remaining text into _.

Nested if statement inside a for loop in bash script

I'm writing a bash script that goes through a for loop which is a list of each hostname, then will test each one if it's responding on port 22, if it is then execute an ssh session, however both the first and second if statements are only executed on the first host in the list, not the rest of the hosts. If the host isn't responding on port 22, I want the script to continue to the next host. Any ideas how to ensure the script runs the ssh on each host in the list? Should this be another for loop?
#!/bin/bash
hostlist=$(cat '/local/bin/bondcheck/hostlist_test.txt')
for host in $hostlist; do
test=$(nmap $host -P0 -p 22 | egrep 'open|closed|filtered' | awk '{print $2}')
if [[ $test = 'open' ]]; then
cd /local/bin/bondcheck/
mv active.current active.fixed
ssh -n $host echo -n "$host: ; cat /proc/net/bonding/bond0 | grep Active" >> active.current
result=$(comm -13 active.fixed active.current)
if [ "$result" == "" ]; then
exit 0
else
echo "$result" | cat -n
fi
else
echo "$host is not responding"
fi
done
exit 0 exits the entire script; you just want to move on to the next iteration of the loop. Use continue instead.
You problem is most likely in the lines
if [ "$result" == "" ]
then
exit 0
else
echo "$result" | cat -n
fi
Here the exit 0 causes the entire script to exit when the $result is empty. You could the way around using :
if [ "$result" != "" ] #proceeding on non-empty 'result'
then
echo "$result" | cat -n
fi

Return value of ping [duplicate]

This question already has an answer here:
checking if grep command returns correct output
(1 answer)
Closed 7 years ago.
I have done a file named hosts.txt which includes some websites, to test the ping on each website with a script. What I want to do with my script is I want to loop through each line that includes different websites, and it should tell if the website is up or down (by measuring the ping command on each)
What my problem is that I don't really know how to get the return value of the ping command, so in case a website is up it should say "'website name' found" or not found. I have been researching, also tried out the ! command and different ways in the if-statement, but none of them seem to work.
My code:
#!/bin/bash
echo
echo "Monitoring hosts from file hosts.txt ..."
echo
echo
egrep -v '^(#|$)' hosts.txt | while read line; do #put the egrep value
#which is the lines in hosts.txt, and loop through each one of them
if [ ping $line ];then
echo "$line is up"
else
echo "$line is not up"
fi
done
echo
You need to use the $? special variable.
For example:
ping $line
pingResponse = $?
if [ $pingResponse -eq 0 ];then
echo "$line is up"
else
echo "$line is not up"
fi
you can test for boolean like:
[[ `ping $line` ]]
.
#!/bin/bash
echo
echo "Monitoring hosts from file hosts.txt ..."
echo
echo
egrep -v '^(#|$)' hosts.txt | while read line; do #put the egrep value
#which is the lines in hosts.txt, and loop through each one of them
if [[ `ping $line` ]];then
echo "$line is up"
else
echo "$line is not up"
fi
done

Checking host availability by using ping in bash scripts

I want to write a script, that would keep checking if any of the devices in network, that should be online all day long, are really online. I tried to use ping, but
if [ "`ping -c 1 some_ip_here`" ]
then
echo 1
else
echo 0
fi
gives 1 no matter if I enter valid or invalid ip address. How can I check if a specific address (or better any of devices from list of ip addresses) went offline?
Ping returns different exit codes depending on the type of error.
ping 256.256.256.256 ; echo $?
# 68
ping -c 1 127.0.0.1 ; echo $?
# 0
ping -c 1 192.168.1.5 ; echo $?
# 2
0 means host reachable
2 means unreachable
You don't need the backticks in the if statement. You can use this check
if ping -c 1 some_ip_here &> /dev/null
then
echo "success"
else
echo "error"
fi
The if command checks the exit code of the following command (the ping). If the exit code is zero (which means that the command exited successfully) the then block will be executed. If it return a non-zero exit code, then the else block will be executed.
I can think of a one liner like this to run
ping -c 1 127.0.0.1 &> /dev/null && echo success || echo fail
Replace 127.0.0.1 with IP or hostname, replace echo commands with what needs to be done in either case.
Code above will succeed, maybe try with an IP or hostname you know that is not accessible.
Like this:
ping -c 1 google.com &> /dev/null && echo success || echo fail
and this
ping -c 1 lolcatz.ninja &> /dev/null && echo success || echo fail
There is advanced version of ping - "fping", which gives possibility to define the timeout in milliseconds.
#!/bin/bash
IP='192.168.1.1'
fping -c1 -t300 $IP 2>/dev/null 1>/dev/null
if [ "$?" = 0 ]
then
echo "Host found"
else
echo "Host not found"
fi
This is a complete bash script which pings target every 5 seconds and logs errors to a file.
Enjoy!
#!/bin/bash
FILE=errors.txt
TARGET=192.168.0.1
touch $FILE
while true;
do
DATE=$(date '+%d/%m/%Y %H:%M:%S')
ping -c 1 $TARGET &> /dev/null
if [[ $? -ne 0 ]]; then
echo "ERROR "$DATE
echo $DATE >> $FILE
else
echo "OK "$DATE
fi
sleep 5
done
FYI,
I just did some test using the method above and if we use multi ping (10 requests)
ping -c10 8.8.8.8 &> /dev/null ; echo $?
the result of multi ping command will be "0" if at least one of ping result reachable,
and "1" in case where all ping requests are unreachable.
up=`fping -r 1 $1 `
if [ -z "${up}" ]; then
printf "Host $1 not responding to ping \n"
else
printf "Host $1 responding to ping \n"
fi
for i in `cat Hostlist`
do
ping -c1 -w2 $i | grep "PING" | awk '{print $2,$3}'
done
This seems to work moderately well in a terminal emulator window. It loops until there's a connection then stops.
#!/bin/bash
# ping in a loop until the net is up
declare -i s=0
declare -i m=0
while ! ping -c1 -w2 8.8.8.8 &> /dev/null ;
do
echo "down" $m:$s
sleep 10
s=s+10
if test $s -ge 60; then
s=0
m=m+1;
fi
done
echo -e "--------->> UP! (connect a speaker) <<--------" \\a
The \a at the end is trying to get a bel char on connect. I've been trying to do this in LXDE/lxpanel but everything halts until I have a network connection again. Having a time started out as a progress indicator because if you look at a window with just "down" on every line you can't even tell it's moving.
I liked the idea of checking a list like:
for i in `cat Hostlist`
do
ping -c1 -w2 $i | grep "PING" | awk '{print $2,$3}'
done
but that snippet doesn't care if a host is unreachable, so is not a great answer IMHO.
I ran with it and wrote
for i in `cat Hostlist`
do
ping -c1 -w2 $i >/dev/null 2>&1 ; echo $i $?
done
And I can then handle each accordingly.
check host every one second and send message when host is reach
while :;do ping -c 1 -w 1 -q 8.8.8.8 &>/dev/null && /root/telegram-send.sh "Host reacheble now" && break || sleep 1;done

Bash loop ping successful

I'm thinking that this needs to be changed to a while clause, at the moment it'll wait till all 10000 pings are done, I need it to return when the ping is successful. The program "say" is on OSX it makes the computer speak.
#!/bin/bash
echo begin ping
if ping -c 100000 8.8.8.8 | grep timeout;
then echo `say timeout`;
else echo `say the internet is back up`;
fi
OK I don't have rights to answer my own question so here's my answer for it after playing around:
Thanks, yeah I didn't know about $? until now. Anyway now I've gone and made this. I like that yours doesn't go forever but in my situation I didn't need it to stop until it's finished.
#!/bin/bash
intertube=0
echo "begin ping"
while [ $intertube -ne 1 ]; do
ping -c 3 google.com
if [ $? -eq 0 ]; then
echo "ping success";
say success
intertube=1;
else
echo "fail ping"
fi
done
echo "fin script"
You probably shouldn't rely on textual output of a command to decide this, especially when the ping command gives you a perfectly good return value:
The ping utility returns an exit status of zero if at least one response was heard from the specified host; a status of two if the transmission was successful but no responses were received; or another value from <sysexits.h> if an error occurred.
In other words, use something like:
((count = 60)) # Maximum number to try.
while [[ $count -ne 0 ]] ; do
ping -c 1 8.8.8.8 # Try once.
rc=$?
if [[ $rc -eq 0 ]] ; then
((count = 1)) # If okay, flag loop exit.
else
sleep 1 # Minimise network storm.
fi
((count = count - 1)) # So we don't go forever.
done
if [[ $rc -eq 0 ]] ; then # Make final determination.
echo `say The internet is back up.`
else
echo `say Timeout.`
fi
You don't need to use echo or grep. You could do this:
ping -oc 100000 8.8.8.8 > /dev/null && say "up" || say "down"
This can also be done with a timeout:
# Ping until timeout or 1 successful packet
ping -w (timeout) -c 1
I use this Bash script to test the internet status every minute on OSX
#address=192.168.1.99 # forced bad address for testing/debugging
address=23.208.224.170 # www.cisco.com
internet=1 # default to internet is up
while true;
do
# %a Day of Week, textual
# %b Month, textual, abbreviated
# %d Day, numeric
# %r Timestamp AM/PM
echo -n $(date +"%a, %b %d, %r") "-- "
ping -c 1 ${address} > /tmp/ping.$
if [[ $? -ne 0 ]]; then
if [[ ${internet} -eq 1 ]]; then # edge trigger -- was up now down
echo -n $(say "Internet down") # OSX Text-to-Speech
echo -n "Internet DOWN"
else
echo -n "... still down"
fi
internet=0
else
if [[ ${internet} -eq 0 ]]; then # edge trigger -- was down now up
echo -n $(say "Internet back up") # OSX Text-To-Speech
fi
internet=1
fi
cat /tmp/ping.$ | head -2 | tail -1
sleep 60 ; # sleep 60 seconds =1 min
done
If you use the -o option, BSD ping (which is also on macOS) will exit after receiving one reply packet.
Further reading: https://www.freebsd.org/cgi/man.cgi?query=ping
EDIT: paxdiablo makes a very good point about using ping’s exit status to your advantage. I would do something like:
#!/usr/bin/env bash
echo 'Begin ping'
if ping -oc 100000 8.8.8.8 > /dev/null; then
echo $(say 'timeout')
else
echo $(say 'the Internet is back up')
fi
ping will send up to 100,000 packets and then exit with a failure status—unless it receives one reply packet, in which case it exits with a success status. The if will then execute the appropriate statement.
Here's my one-liner solution:
screen -S internet-check -d -m -- bash -c 'while ! ping -c 1 google.com; do echo -; done; echo Google responding to ping | mail -s internet-back my-email#example.com'
This runs an infinite ping in a new screen session until there is a response, at which point it sends an e-mail to my-email#example.com. Useful in the age of e-mail sent to phones.
(You might want to check that mail is configured correctly by just running echo test | mail -s test my-email#example.com first. Of course you can do whatever you want from done; onwards, sound a bell, start a web browser, use your imagination.)
I liked paxdiablo's script, but wanted a version that ran indefinitely. This version runs ping until a connection is established and then prints a message saying so.
echo "Testing..."
PING_CMD="ping -t 3 -c 1 google.com > /dev/null 2>&1"
eval $PING_CMD
if [[ $? -eq 0 ]]; then
echo "Already connected."
else
echo -n "Waiting for connection..."
while true; do
eval $PING_CMD
if [[ $? -eq 0 ]]; then
echo
echo Connected.
break
else
sleep 0.5
echo -n .
fi
done
fi
I also have a Gist of this script which I'll update with fixes and improvements as needed.

Resources