code works but won't continue to run the loop stuck in the inner loop not sure where the problem is, or maybe port scan just takes alot of time
#!/bin/bash
up()
{
ping -c 1 $1 > /dev/null
[ $? -eq 0 ] && echo IP: $i is up.
}
for i in 192.168.0.{1..255}
do
up $i & disown
for port in {1..100};do
2>/dev/null echo > /dev/tcp/$i/$port
if [ $? == 0 ]
then
{
echo "port $port is open"
continue
}
fi
done
done
exit
Scan Ping + TCP in bash
I've tried to limit script to 8182 forks in order to stay polite.
This script scan /etc/services, then could scan all (desired) ports. (see comments).
Full scan of my complex private subnet take more than 5 minutes to complete (scanning 303 ports on 255 hosts, found 27 up)!
#!/bin/bash
BaseIP=${1:-192.168.1}
ports=(21 22 25 80 443 9100)
# ports=({1..100}) # Uncomment this for ports 1-100
while IFS=$' \t\r\n/' read serv port prot comm ;do
[ "$prot" = "tcp" ] && printf -v $prot[$port] %s "$serv"
done </etc/services
# ports=(${!tcp[#]}) # Uncomment this for all known ports
isup() { ping -W 1 -c1 -n $1 &>/dev/null && printf "IP: %-17sis up.\n" $1;}
tstport() { local _tst _prot=${3:-tcp}; local -n _var=$_prot[$2]
{
exec {_tst}<>/dev/$_prot/$1/$2 && exec {_tst}<&- &&
printf "IP: %-16s port %6d open (%s)\n" $1 $2 ${_var:-unassigned}
} 2>/dev/null
}
step=$((8180/(${#ports[#]}+1)))
for ((i=1;i < 255;i+=step)) {
max=$((i+step>255?255:i+step))
for ((l=i;l<max;l++)) {
isup $BaseIP.$l &
exec {dummy}< <(:)
for port in ${ports[#]} ;do
exec {dummy2}< <(:)
tstport $BaseIP.$l $port & read -u $dummy2 -t .02
exec {dummy2}<&-
done &
read -u $dummy -t .02
exec {dummy}<&-
} |
sed -une /./p
}
Sorted ouptut could look like:
IP: 192.168.1.1 is up.
IP: 192.168.1.3 is up.
IP: 192.168.1.3 port 22 open (ssh)
IP: 192.168.1.15 is up.
IP: 192.168.1.15 port 22 open (ssh)
IP: 192.168.1.15 port 139 open (netbios-ssn)
IP: 192.168.1.15 port 445 open (microsoft-ds)
IP: 192.168.1.15 port 515 open (printer)
IP: 192.168.1.39 is up.
IP: 192.168.1.39 port 22 open (ssh)
Related
I want to ping in a for loop using dynamic names.
When i try ping -c1 -w1 10.0.0.10 > /dev/null it works perfectly, but when i try to change my static adress into a dynamic one, i'll get an error.
declare -A array=([piotr_pc]=10.0.0.10 )
for item in ${!array[*]}
do
file=$(grep $item homesystem/web/openvpn-status.log | tr 'm\n' 'p,')
IFS=','
for x in $file
do
eval $item+=\("$x"\)
done
eval echo \${$item[9]}
if ping -c1 -w1 eval echo \${$item[9]} > /dev/null; then
echo eval echo \${$item[9]} "ONLINE" $NOW
echo "UPDATE openvpn SET status='ONLINE', last_online='$NOW' , Common Name = '${piotr_pc[0]}', Real Address = '${piotr_pc[1]}', Bytes Received = '${piotr_pc[2]}', Bytes Sent = '${piotr_pc[3]}', Connected Since = '${piotr_pc[4]}', Virtual Address = '${piotr_pc[5]}' , Last Ref = '${piotr_pc[8]}' WHERE ip_vpn='${piotr_pc[5]}'"
#mysql -uphptest -pphphaslo openwrt -e "UPDATE openvpn SET status='ONLINE', last_online='$NOW' WHERE ip_vpn='$ip'"
else
eval echo \${$item[9]} "OFFLINE"
#mysql -uphptest -pphphaslo openwrt -e "UPDATE openvpn SET status='OFFLINE' WHERE ip_vpn='$ip'"
fi
done
Result:
root#VigoradoNetwork:/www1# ./ping.sh
10.0.0.10
BusyBox v1.28.3 () multi-call binary.
Usage: ping [OPTIONS] HOST
Send ICMP ECHO_REQUEST packets to network hosts
-4,-6 Force IP or IPv6 name resolution
-c CNT Send only CNT pings
-s SIZE Send SIZE data bytes in packets (default 56)
-t TTL Set TTL
-I IFACE/IP Source interface or IP address
-W SEC Seconds to wait for the first response (default 10)
(after all -c CNT packets are sent)
-w SEC Seconds until ping exits (default:infinite)
(can exit earlier with -c CNT)
-q Quiet, only display output at start
and when finished
-p HEXBYTE Pattern to use for payload
10.0.0.10 OFFLINE
I want to change this 10.0.0.10 with eval echo \${$item[9]} but i dont know how to do this.
I'm not sure if i understood you correctly but following may be helpful if you are running multiple pings to hosts using a hostlist file.
#!/bin/bash
echo "`date` Starting the Ping Check...."
function pingHost () {
hostTarget=${1}
# send stdout/stderr to /dev/null since all we need is the return code
ping -c2 ${hostTarget} >/dev/null 2>&1 &&
echo Host ${hostTarget} is SUCCESS||
echo Host ${hostTarget} is FAILED
}
data=$(<my_hostlist) # Place your hostlist here example "Master_hostlist"
for line in ${data}
do
# call our function and place the call in the background
pingHost ${line} &
done
# wait for all outstanding background jobs to complete before continuing
wait
# [optional] let operator know we're done.
echo "Completed #=> `date`"
I am trying to cycle through some ports for connecting via ssh. New to shell/bash not quite sure how to accomplish this.
startingPort=xxxx
endingPort=yyyy
ssh(){
ssh admin#localhost -p $startingPort
}
the output of an invalid port is ssh: connect to host localhost port 8801: Connection refused
I need to capture this and then try the next port in the range
I am trying to iterate through the port numbers until i see
Password authentication
Password:
To get the output of the ssh command, you can check it with "$?".
As an example, if you want to log errors :
//inside the loop (of muzido answer)
ssh admin#localhost -p $port
if [ "$?" -ne 0 ] ; then
//write into logfile
fi
Thank you muzido and Theo Pnv; the two answers combined helped me get this task accomplished..
log_file=/directory/log_file.txt
startingPort=8801
endingPort=8899
port=''
sshToStuff(){
for (( port=$startingPort; port<=$endingPort; port++ ))
do
if [ "$?" -ne 0 ] ; then
echo "`date -u`" " ssh: connect to host localhost port $port: Connection refused" >> $log_file2;
fi
ssh admin#localhost -p $port
done
}
sshToKaraf
try something like this;
#!/bin/bash
startingPort=10
endingPort=40
for (( port=$startingPort; port<=$endingPort; port++ ))
do
ssh admin#localhost -p $port
done
I would like to scan multiple ports in multiple hosts. I used this script but it takes long time to show the result.
#!/bin/bash
hosts=(
"server1"
"server2"
)
for host in "${hosts[#]}"
do
echo "=========================================="
echo "Scanning $host"
echo "=========================================="
for port in {21,22,80}
do
echo "" > /dev/tcp/$host/$port && echo "Port $port is open"
done 2>/dev/null
done
Some people suggested to use telnet or NetCat instead but i prefer to do it without installing any new packages. So, are there any ways to speed it up by multithreading or other way.
You could use GNU Parallel to run all the checks in parallel. I am not the best at using it, and #OleTange (the author) normally has to correct me but I keep trying. So, let's try your case, by building up to it slowly:
parallel echo {1} {2} ::: 192.168.0.1 192.168.0.8 ::: 21 22 80
192.168.0.8 22
192.168.0.8 80
192.168.0.8 21
192.168.0.1 80
192.168.0.1 22
192.168.0.1 21
looks kind of hopeful to me. Then I add in -k to keep the results in order, and I supply a function that takes those IP addresses and ports as arguments:
parallel -k 'echo "" > /dev/tcp/{1}/{2} && echo {1}:{2} is open' ::: 192.168.0.1 192.168.0.8 ::: 21 22 80 2>/dev/null
192.168.0.1:80 is open
192.168.0.8:21 is open
192.168.0.8:22 is open
192.168.0.8:80 is open
This will run 8 jobs in parallel if your CPU has 8 cores, however echo is not very resource intensive so you can probably run 32 in parallel, so add -j 32 after the -k.
If you wanted to stick closer to your own script, you can do it like this:
#!/bin/bash
hosts=(
"192.168.0.1"
"192.168.0.8"
)
for host in "${hosts[#]}"
do
for port in {21,22,80}
do
echo "(echo > /dev/tcp/$host/$port) 2>/dev/null && echo Host:$host Port:$port is open"
done
done | parallel -k -j 32
Basically, instead of running your commands, I am just sending them to the stdin of parallel so it can do its magic with them.
You could run all three pokes in the background, then wait for them all to finish, and probably slash the running time to 1/3.
for port in 21 22 80; do
echo "" > /dev/tcp/$host/$port 2>/dev/null &
pid[$port]=$!
done
for port in 21 22 80; do
wait $pid[$port] && echo "Port $port" is open"
done
You could add parallelism by running multiple hosts in the background, too, but that should be an obvious extension.
#!/bin/bash
function alarm {
local timeout=$1; shift;
# execute command, store PID
bash -c "$#" &
local pid=$!
# sleep for $timeout seconds, then attempt to kill PID
{
sleep "$timeout"
kill $pid 2> /dev/null
} &
wait $pid 2> /dev/null
return $?
}
function scan {
if [[ -z $1 || -z $2 ]]; then
echo "Usage: ./scanner <host> <port, ports, or port-range>"
echo "Example: ./scanner google.com 79-81"
return
fi
local host=$1
local ports=()
# store user-provided ports in array
case $2 in
*-*)
IFS=- read start end <<< "$2"
for ((port=start; port <= end; port++)); do
ports+=($port)
done
;;
*,*)
IFS=, read -ra ports <<< "$2"
;;
*)
ports+=($2)
;;
esac
# attempt to write to each port, print open if successful, closed if not
for port in "${ports[#]}"; do
alarm 1 "echo >/dev/tcp/$host/$port" &&
echo "$port/tcp open" ||
echo "$port/tcp closed"
done
}
scan $1 $2
I am required to test at least 130 ip addresses and ports.
I am hoping to write a bash script such that it reads the ip address and ports from an input file.
I have the following
while read line
do
telnet $line >> $2
done < $1
This is a crappy code as it cannot determine whether its connected or failed, and I have to rely on its auto escape character to disconnect from a connection.
How can I improvise this such that it updates $2 with the status quickly?
I am working on Redhat and do not have netcat or expect installed..
As other stackoverflower's said, I would recommend using nmap or netcat if avilable.
However, if you cannot use those software, you can use bash's builtin /dev/tcp/<host>/<port> instead.
http://www.gnu.org/software/bash/manual/bashref.html#Redirections
I could'nt figure out which version of bash you are using, but /dev/tcp/... seems to implemented since some old bash.
#!/bin/bash
echo "scanme.nmap.org 21
scanme.nmap.org 22
scanme.nmap.org 23
scanme.nmap.org 79
scanme.nmap.org 80
scanme.nmap.org 81" | \
while read host port; do
r=$(bash -c 'exec 3<> /dev/tcp/'$host'/'$port';echo $?' 2>/dev/null)
if [ "$r" = "0" ]; then
echo $host $port is open
else
echo $host $port is closed
fi
done
This produces
scanme.nmap.org 21 is closed
scanme.nmap.org 22 is open
scanme.nmap.org 23 is closed
scanme.nmap.org 79 is closed
scanme.nmap.org 80 is open
scanme.nmap.org 81 is closed
UPDATED: The following can do timeout.
Although it may seem little tricky, idea is just to kill the child process after some timeout.
Bash script that kills a child process after a given timeout
#!/bin/bash
echo "scanme.nmap.org 80
scanme.nmap.org 81
192.168.0.100 1" | (
TCP_TIMEOUT=3
while read host port; do
(CURPID=$BASHPID;
(sleep $TCP_TIMEOUT;kill $CURPID) &
exec 3<> /dev/tcp/$host/$port
) 2>/dev/null
case $? in
0)
echo $host $port is open;;
1)
echo $host $port is closed;;
143) # killed by SIGTERM
echo $host $port timeouted;;
esac
done
) 2>/dev/null # avoid bash message "Terminated ..."
this produces
scanme.nmap.org 80 is open
scanme.nmap.org 81 is closed
192.168.0.100 1 timeouted
since 192.168.100 does not exist in my local network.
A slight update to the accepted answer:
#!/bin/bash
# supertelnet 127.0.0.1:3306 10.10.10.45:22
(
TCP_TIMEOUT=3
for hostport in ${#}; do
a=(${hostport//:/ })
host=${a[0]}
port=${a[1]}
(CURPID=$BASHPID;
(sleep $TCP_TIMEOUT;kill $CURPID) &
exec 3<> /dev/tcp/$host/$port
) 2>/dev/null
case $? in
0)
echo $host $port is open;;
1)
echo $host $port is closed;;
143) # killed by SIGTERM
echo $host $port timeouted;;
esac
done
) 2>/dev/null # avoid bash message "Terminated ..."
I find this to be a lot more friendly as a script.
Pure bash nmap replacment:
Sorry for comming so late on this question.
Speed parallelized process
This could be a lot quicker if all probe are done together:
TargetList=(
scanme.nmap.org:21 scanme.nmap.org:22 scanme.nmap.org:23
scanme.nmap.org:79 scanme.nmap.org:80 scanme.nmap.org:81
)
checkTcpConn() {
local line testfd bpid=$BASHPID
( sleep 3 && kill -INT $bpid && echo $1 timeout) &
if exec {testfd}<>/dev/tcp/${1/:/\/};then
echo >&$testfd $'\r\n\r\n'
read -ru $testfd -t 1 line
[[ $line ]] &&
echo $1 open $line ||
echo $1 open
exec {testfd}<&-
else
echo $1 closed
fi
}
for target in ${TargetList[#]};do
checkTcpConn $target &
done 2>/dev/null | sort
will output quickly:
scanme.nmap.org:21 closed
scanme.nmap.org:22 open SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.13
scanme.nmap.org:23 closed
scanme.nmap.org:79 closed
scanme.nmap.org:80 open HTTP/1.1 400 Bad Request
scanme.nmap.org:81 closed
or worst:
for target in scanme.nmap.org:{{1..1024},3128,3306,5432,5900,8080};do
checkTcpConn $target &
sleep .002
done 2>/dev/null | grep open
scanme.nmap.org:22 open SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.13
scanme.nmap.org:80 open HTTP/1.1 400 Bad Request
And with a timeout:
for target in scanme.nmap.org:2{2,1} 192.168.210.123:1 ;do
checkTcpConn $target &
done 2>/dev/null |
sort
192.168.210.123:1 timeout
scanme.nmap.org:21 closed
scanme.nmap.org:22 open SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.13
Nota The last pipe done 2>/dev/null | sort is required in order to avoid job control messages. For showing raw output, use
...
done 2>/dev/null | cat
Is there any way, using basic Unix commands, to find the next unused port number, starting at port 4444 and going upwards? I'm ssh'ed (via openssh) into a Windows XP machine, running Cygwin tools and using a bash shell.
Thanks, - Dave
Try this:
for port in $(seq 4444 65000); do echo -ne "\035" | telnet 127.0.0.1 $port > /dev/null 2>&1; [ $? -eq 1 ] && echo "unused $port" && break; done
where
seq 4444 65000 - port range for check
echo -ne "\035" - escape character to force close telnet session (^])
if telnet finishes with exit code 1 that mean connection refused:
$ telnet 127.0.0.1 4444
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
telnet: Unable to connect to remote host
$ echo $?
1
else we decided that connection was success with exit code 0.
EDIT:
Special for cygwin: You need to install additional package inetutils that is contain telnet port and use the script as follows:
for port in $(seq 4444 65000); do echo -ne "\035" | /usr/bin/telnet 127.0.0.1 $port > /dev/null 2>&1; [ $? -eq 1 ] && echo "unused $port" && break; done
Same as above, but written as a function
function get_unused_port() {
for port in $(seq 4444 65000);
do
echo -ne "\035" | telnet 127.0.0.1 $port > /dev/null 2>&1;
[ $? -eq 1 ] && echo "$port" && break;
done
}
FREE_PORT="$(get_unused_port)"
echo $FREE_PORT
The following function doesn't depend on telnet/netcat as it generates a random port in the local port range and compares it with a list of ports currently used by running applications.
Should work on any *nix that supports proc filesystem. Generates a free ephemeral port to be used by your application.
function EPHEMERAL_PORT(){
while true; do
LISTENING_PORTS=$(cat /proc/net/tcp | awk 'NR >1 {print $2}' | awk -F':' '{print $2}');
LISTENING_PORTS=$(for PORT in ${LISTENING_PORTS}; do echo $((16#${PORT})); done|sort -g);
# echo "32768 60999" | read LPORT UPORT
read LPORT UPORT < /proc/sys/net/ipv4/ip_local_port_range
MPORT=$[$LPORT + ($RANDOM % $UPORT)];
if (echo "${LISTENING_PORTS[#]}" | grep -xqv $MPORT); then
echo $MPORT;
break;
fi
done
}
Apparently TCP connections can be used as file descriptors on linux. The following function uses that technique and should be faster than the previous one.
function EPHYMERAL_PORT(){
LPORT=32768;
UPORT=60999;
while true; do
MPORT=$[$LPORT + ($RANDOM % $UPORT)];
(echo "" >/dev/tcp/127.0.0.1/${MPORT}) >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo $MPORT;
return 0;
fi
done
}
This is a cross platform function that uses osquery to get a list of listening ports. Should also work on Windows.
function EPHYMERAL_PORT(){
while true; do
echo "32768 60999" | read LPORT UPORT
MPORT=$[$LPORT + ($RANDOM % $UPORT)];
LISTENING_PORTS=$(osqueryi --header=false --list "select port from listening_ports order by port");
if (echo "${LISTENING_PORTS[#]}" | grep -xqv $MPORT); then
echo $MPORT;
break;
fi
done
}
Usage instructions. Bind the output to a variable and use in scripts. Tested on Ubuntu 16.04
root#ubuntu:~> EPHYMERAL_PORT
59453
root#ubuntu:~> PORT=$(EPHYMERAL_PORT)