Creating simple if statement in Python when pining IP address - python

I'm using: Windows I'm trying to create a simple if statement when pinging ip address
import os
hostname = "192.168.8.8." #example
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
print hostname, 'is down'
else:
print hostname, 'is up'
print response
I'm pretty new at this, but no matter what ip address I put, valid or not, it says it's up.

os.system() returns the process exit value. 0 means success.
In your case it is getting executed successfully and hence it is returning 0. All you have to do is get the complete output from the ping command and then do string comparison to find out if that IP is alive.
You need to use subprocess's checkoutput method
import subprocess
hostname = "google.com"
batcmd="ping -n 1 " + hostname
result = subprocess.check_output(batcmd, shell=True)
if "Received = 1" in result:
print "Is UP"
else:
print "Is Down"

Use a variation of my answer here removing the interface argument subprocess.check_call:
from subprocess import check_call, CalledProcessError, PIPE
def is_reachable(i, add):
command = ["ping", "-c", i, add]
try:
check_call(command,sdout=PIPE)
return True
except CalledProcessError as e:
return False
if is_reachable("3", "127.0.0.01"):
# host is reachable
else:
# not reachable
On windows you may need to add the args "-w", "2999" to get something other than 0 returned for the errorlevel for unreachable hosts as the return code will be zero even for unsuccessful calls, windows-7-get-no-reply-but-sets-errorlevel-to-0
You could also use check_output, specifically checking if Destination host unreachable was in the output:
return "Destination host unreachable" in check_output(command)

You did everything okay, The only issue is that you confused the correct output which is 0 with the wrong output, which is everything above 0.
import os
hostname = "192.168.8.8." #example
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
print hostname, 'is up'
else:
print hostname, 'is down'
print response

Related

Paramiko sending text to psuedo shell

Testing sending commands to IoT devices that drops the user into a python script instead of a bash shell.
i.e. in /etc/passwd - admin:x:1000:0:admin:/home/admin:/home/admin/IoT.py
So cant use the normal bash exec_commands to talk to the python script. Basically once it connects it needs the send a command string and receive the output. Below the script reads IP addresses from a text file, whats the correct way to send and receive commands
#!/usr/bin/env python
import paramiko
import sys
def LogonSSH(ipAddress) :
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for line in open(ipAddress, "r").readlines() :
ipAddr = line.strip()
username='admin'
password='admin'
try :
print "[+] Trying %s with username: %s password: %s " % (ipAddr, username, password)
ssh.connect(ipAddr, username=username, password=password)
except paramiko.AuthenticationException:
print "[x] %s - could not log in" % (ipAddr)
continue
stdin, stdout, stderr = ssh.exec_command('help')
stdin.flush()
stdin.write('help\n')
out = stdout.read()
stdin.flush()
print out
ssh.close()
break
if __name__ == "__main__" :
LogonSSH(sys.argv[1])
Below changes might help you. Just make send and recv, recv only takes the last commands output, but you need to consider:
Put some sleep after sending command (just trial and error)
Some tricks on output data, because it has invisible string parts such as (<pre>..</pre>)
Some output data might be too big to handle > 65100 bytes of recv, just check Paramiko Docs for recv method.
#!/usr/bin/env python
import paramiko
import sys
def LogonSSH(ipAddress) :
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for line in open(ipAddress, "r").readlines() :
ipAddr = line.strip()
username='admin'
password='admin'
try:
print "[+] Trying %s with username: %s password: %s " % (ipAddr, username, password)
ssh.connect(ipAddr, port=22, username=uname, password=pin, timeout=240,banner_timeout=250, auth_timeout=500)
my_ssh_shell = ssh.invoke_shell()
except Exception as ex:
print("Some exception occured:" + str(ex))
continue
my_ssh_shell.send(bytes("help" + "\x0D", 'utf-8'))
result_screen = my_ssh_shell.recv(65100).decode('ascii')
print("Your SSH -help- command returns:" + str(result_screen))
my_ssh_shell.close()
break
if __name__ == "__main__" :
LogonSSH(sys.argv[1])
Edit: Just change it to any exception for connection, and also some additional paramters on connection string.
The following code will get the MOTD, but send still not working
my_ssh_shell = ssh.invoke_shell()
my_ssh_shell.settimeout(2)
while True :
data = my_ssh_shell.recv(1024).decode('ascii')
if len(data) < 1 :break
print(data)
return
#### DOESNT SEND HERE OR GET RECEIVE RESULTS#########
# my_ssh_shell.send('help\n')
# while True :
# data = my_ssh_shell.recv(1024).decode('ascii')
# if len(data) < 1 :break
# print(data)
# return
my_ssh_shell.close()

How to get ttl value in pyping python

The below program only print if the server is up or down using pyping, but I need to print the output with TTL (time to live) value.
import pyping
servers = (
'192.168.1.1',
'192.168.1.2',
'192.168.1.3'
)
temp = []
for server in servers:
checker = pyping.ping(server)
if checker.ret_code == 0:
body = "%s Server is UP" % (server)
temp.append(body)
else:
body = "%s Server is Down" % (server)
temp.append(body)
print(temp)
Guys if you have any other ideas to get ttl value kindly post it..
use Popen from subprocess module
you can use returncode of command success if >0 then not success
import subprocess
import re
p = subprocess.Popen(["ping","www.google.com"], stdout=subprocess.PIPE)
res=p.communicate()[0]
if p.returncode > 0:
print('server error')
else:
pattern = re.compile('TTL=\d*')
print(pattern.search(str(res)).group())
OUT
TTL=56
on linux pass the one more -c along with command to avoid endless ping

Python Check if Condition in Loop Changes

I have created a small python script to monitor if an OS (Linux) is able to ping a certain ip address of 10.0.0.1 (router on LAN). This first script works fine but I have to execute the script to have it evaluate the condition each time.
I think I understand that this script simply exits after the condition is evaluated. I tried including a while else loop in the second example below that evaluates the return of the OS call and place this function call in the loop to keep checking if the router was plugged back into the LAN.
Is the correct approach to define a function to evaluate the ping status? I tried adding a function in the last example but it doesn't seem to update.
My goal is to run this script once and have it detect is 10.0.0.1 is up or down when I unplug it from the network or plug it back in.
import os
import time
ip = "10.0.0.1"
response = os.system("ping -c 1 " +ip)
if response != 0:
print ip, 'is down'
time.sleep(3)
else:
print ip, 'is up!'
I tried adding the while else loop but the condition doesn't seem to get updated.
import os
import time
ip = "10.0.0.1"
response = os.system("ping -c 1 " +ip)
while response != 0:
print ip, 'is down'
time.sleep(3)
else:
print ip, 'is up!'
I even tried defining a fuction to evaluate the condition for every iteration of the loop..
import os
import time
ip = "10.0.0.1"
response = os.system("ping -c 1 " +ip)
def checkstatus():
response = os.system("ping -c 1 " +ip)
while response != 0:
print ip, 'is down'
time.sleep(3)
checkstatus()# trying to evaluate if status has changed
while response != 1:
print ip, 'is up'
time.sleep(3)
checkstatus()# trying to evaluate if status has changed
EDIT
This is how I changed the script and now it works..Just need to slow down the network unreachable stdout.
import os
import time
ip = "10.0.0.1"
while True:
response = os.system("ping -c 1 " + ip)
if response == 0:
print'connected'
time.sleep(.5)
New output NOTICE print statement connected appears as connected
--- 10.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.383/0.383/0.383/0.000 ms
**connected**
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.308 ms
--- 10.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.308/0.308/0.308/0.000 ms
***connected***
New Output after unplugged for a few seconds (floods screen)
connect: Network is unreachable
connect: Network is unreachable
connect: Network is unreachable
connect: Network is unreachable
connect: Network is unreachable
Nothing too bad but worried this will use many CPU cycles as this script will
be running on a raspberry pi.
The mistake you make is that you look for changes in response, which doesn't reflect the network status changes unless you repeat the assignment to it via response = os.system("ping -c 1 " +ip).
Apart from including the assignment inside your loop (as suggested by DeepSpace) you can also change the loop check itself to correctly reflect network status changes (according to your method):
while os.system("ping -c 1 " +ip):
print ip, 'is down'
time.sleep(3)
Similarly, when using checkstatus() you'd need to either include response = checkstatus() in the loop or use it in the check: while checkstatus():.
The last version of your code has a couple of extra problems:
typically the return code of a program is 0 on success, but it may have multiple non-zero return codes, so your != 1 check might not work as you'd expect, better use == 0 check instead.
the sequenced potentially endless while statements won't actually complete unless a certain sequence of the connection state happens. Since your goal is to simply run once and find out the current state of the connection the code would better not depend on such sequence.
Maybe something like this instead?
if os.system("ping -c 1 " +ip):
print ip, 'is down'
else:
print ip, 'is up'
Or, if you prefer one-liners:
print ip, 'is ' + 'down' if os.system("ping -c 1 " +ip) else 'up'
For your second attempt (with the function), I believe what is happening is that response is being defined as a local variable of the function checkstatus, which is separate from the global varriable response. To reassign the global from the function (and not make a local variable), add the line global response to the top of the function body.
The naive way would be to use while True:
ip = "10.0.0.1"
while True:
response = os.system("ping -c 1 " + ip)
if response == 0:
break # or do anything else
time.sleep(3)
A better way is to have the script make a single call to os.system then use crontab or Windows Scheduler to run it every X amount of time.

Python: Execute a command in Cisco Router on successful ping else print error

The following code fetches IP address (Cisco Router) from a text file and executes the mentioned command and prints the resultant output on to a file. Here am trying to first test the reach-ability of the device by using PING, on successful ping response commands should be executed else should print an error and move to the next host. Please help me on how to achieve this. I am a newbie.
Here is my code,
import paramiko
import sys
import os
import subprocess
with open('C:\Python27\Testing\Fetch.txt') as f:
for line in f:
line = line.strip()
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
dssh.connect(line, username='cisco', password='cisco')
stdin, stdout, stderr = dssh.exec_command('sh ip ssh')
mystring = stdout.read()
print mystring
f = open('C:\Python27\Testing\output.txt', 'a+')
f.write(mystring)
f.close()
dssh.close()
Input file Fetch.txt looks like this,
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
10.0.0.5
I scoured through the forum and achieved just about what I am looking for.. If all the IP addresses are reachable in that list, the script works just fine. But if any one of the IP address is unreachable then the script ends abruptly without proceeding to the next IP address. I realize that am doing something wrong here, I just need that little bit of help to get this working..... Please help out.
import paramiko
import sys
import os
import subprocess
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
with open('C:\Python27\Testing\Fetch.txt') as f:
for line in f:
line = line.strip()
with open(os.devnull, "wb") as limbo:
ip = line
result = subprocess.Popen(["ping", "-n", "1", "-w", "200", ip],
stdout=limbo, stderr=limbo).wait()
if result:
print ip, "Down"
else:
print ip, "Reachable"
dssh.connect(line, username='cisco', password='cisco')
stdin, stdout, stderr = dssh.exec_command('sh ip ssh')
mystring = stdout.read()
print mystring
f = open('C:\Python27\Testing\output.txt', 'a+')
f.write('\n' + ip + '\n' + mystring)
f.close()
dssh.close()
You ideally don't have to test if a host is pingable first using a separate if statement..paramiko comes inbuilt with a lot of exception checking ..using this along the socket module..your program can be written in a cleaner fashion without having to use subprocesses..
import paramiko
import socket
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ips = [i.strip() for i in open("C:\Python27\Testing\Fetch.txt")] # creates a list from input file
for ip in ips:
try:
dssh.connect(ip, username='cisco', password='cisco', timeout=4)
stdin, stdout, stderr = ssh.exec_command('sh ip ssh')
print ip + '===' + stdout.read()
ssh.close()
except paramiko.AuthenticationException:
print ip + '=== Bad credentials'
except paramiko.SSHException:
print ip + '=== Issues with ssh service'
except socket.error:
print ip + '=== Device unreachable'
this will catch other exceptions like bad credentials and other issues with ssh service
You could try using fabric which is made for executing SSH commands on multiple machines.
This is just a snippet i threw together but it should show you the way to go.
from fabric.api import run, execute ,env
class Fetcher:
def __init__(self,hosts=[]):
env.hosts= hosts
env.warn_only = True # needed to not abort on pingtimout or other errs
def getclock(self)
run('sh clock')
def fetch(self):
results = execute(self.getclock,hosts=env.hosts)
if __name__ == '__main__':
hosts = loadfromtxt(hosts.txt)
f = Fetcher(hosts=hosts)
f.fetch()
I recall an example of python threading, either in the docs or in a book I read (don't remember the source) that does something like what you're trying to do. Something like this should work:
import sys
import os
import subprocess
from threading import Thread
class Pinger(Thread):
def __init__ (self, ip):
Thread.__init__(self)
self.ip = ip
self.status = False
def __repr__(self):
return "Pinger for '%s' status '%s'" % (self.ip, self.status)
def run(self):
with open(os.devnull, "wb") as limbo:
# Changed the arguments because I don't have a windows ping.exe to test it on
result = subprocess.Popen(["ping", "-c", "2", "-q", self.ip],
stdout=limbo, stderr=limbo).wait()
if result:
# print self.ip, "Down"
self.status = False
else:
# print self.ip, "Reachable"
self.status = True
hosts = []
with open('Fetch.txt') as f:
for line in f:
host = Pinger(line.rstrip())
# print host
hosts.append(host)
host.start()
for host in hosts:
host.join()
if host.status:
print "Host '%s' is up" % host.ip
#### Insert your ssh exec code here ####
# dssh.connect(host.ip, username='cisco', password='cisco')
# etc.
else:
print "Host '%s' is down" % host.ip
Why do you need Paramiko module or to create an input if python can do itself ?
#!/usr/bin/python
import os
hostname = raw_input('Enter the Router Name: ')
routers = hostname.split(',')
print routers
for hostname in routers:
response = os.system("ping -c5 " + hostname)
if response == 0:
print(hostname, 'is up!')
else:
print(hostname, 'is down!')

Pinging servers in Python

In Python, is there a way to ping a server through ICMP and return TRUE if the server responds, or FALSE if there is no response?
If you don't need to support Windows, here's a really concise way to do it:
import os
hostname = "google.com" #example
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
print hostname, 'is up!'
else:
print hostname, 'is down!'
This works because ping returns a non-zero value if the connection fails. (The return value actually differs depending on the network error.) You could also change the ping timeout (in seconds) using the '-t' option. Note, this will output text to the console.
This function works in any OS (Unix, Linux, macOS, and Windows)
Python 2 and Python 3
EDITS:
By #radato os.system was replaced by subprocess.call. This avoids shell injection vulnerability in cases where your hostname string might not be validated.
import platform # For getting the operating system name
import subprocess # For executing a shell command
def ping(host):
"""
Returns True if host (str) responds to a ping request.
Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
"""
# Option for the number of packets as a function of
param = '-n' if platform.system().lower()=='windows' else '-c'
# Building the command. Ex: "ping -c 1 google.com"
command = ['ping', param, '1', host]
return subprocess.call(command) == 0
Note that, according to #ikrase on Windows this function will still return True if you get a Destination Host Unreachable error.
Explanation
The command is ping in both Windows and Unix-like systems.
The option -n (Windows) or -c (Unix) controls the number of packets which in this example was set to 1.
platform.system() returns the platform name. Ex. 'Darwin' on macOS.
subprocess.call() performs a system call. Ex. subprocess.call(['ls','-l']).
There is a module called pyping that can do this. It can be installed with pip
pip install pyping
It is pretty simple to use, however, when using this module, you need root access due to the fact that it is crafting raw packets under the hood.
import pyping
r = pyping.ping('google.com')
if r.ret_code == 0:
print("Success")
else:
print("Failed with {}".format(r.ret_code))
import subprocess
ping_response = subprocess.Popen(["/bin/ping", "-c1", "-w100", "192.168.0.1"], stdout=subprocess.PIPE).stdout.read()
For python3 there's a very simple and convenient python module ping3: (pip install ping3, needs root privileges).
from ping3 import ping, verbose_ping
ping('example.com') # Returns delay in seconds.
>>> 0.215697261510079666
This module allows for the customization of some parameters as well.
Programmatic ICMP ping is complicated due to the elevated privileges required to send raw ICMP packets, and calling ping binary is ugly. For server monitoring, you can achieve the same result using a technique called TCP ping:
# pip3 install tcping
>>> from tcping import Ping
# Ping(host, port, timeout)
>>> ping = Ping('212.69.63.54', 22, 60)
>>> ping.ping(3)
Connected to 212.69.63.54[:22]: seq=1 time=23.71 ms
Connected to 212.69.63.54[:22]: seq=2 time=24.38 ms
Connected to 212.69.63.54[:22]: seq=3 time=24.00 ms
Internally, this simply establishes a TCP connection to the target server and drops it immediately, measuring time elapsed. This particular implementation is a bit limited in that it doesn't handle closed ports but for your own servers it works pretty well.
Because I like to have my Python program universal on version 2.7 and 3.x and on platform Linux, Mac OS and Windows, I had to modify the existing examples.
# shebang does not work over all platforms
# ping.py 2016-02-25 Rudolf
# subprocess.call() is preferred to os.system()
# works under Python 2.7 and 3.4
# works under Linux, Mac OS, Windows
def ping(host):
"""
Returns True if host responds to a ping request
"""
import subprocess, platform
# Ping parameters as function of OS
ping_str = "-n 1" if platform.system().lower()=="windows" else "-c 1"
args = "ping " + " " + ping_str + " " + host
need_sh = False if platform.system().lower()=="windows" else True
# Ping
return subprocess.call(args, shell=need_sh) == 0
# test call
print(ping("192.168.17.142"))
using socket package in python3:
import socket
def ping_server(server: str, port: int, timeout=3):
"""ping server"""
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
except OSError as error:
return False
else:
s.close()
return True
My version of a ping function:
Works on Python 3.5 and later, on Windows and Linux.
On Windows, returns False if the ping command fails with "Destination Host Unreachable".
And does not show any output, either as a pop-up window or in command line.
import platform, subprocess
def ping(host_or_ip, packets=1, timeout=1000):
''' Calls system "ping" command, returns True if ping succeeds.
Required parameter: host_or_ip (str, address of host to ping)
Optional parameters: packets (int, number of retries), timeout (int, ms to wait for response)
Does not show any output, either as popup window or in command line.
Python 3.5+, Windows and Linux compatible
'''
# The ping command is the same for Windows and Linux, except for the "number of packets" flag.
if platform.system().lower() == 'windows':
command = ['ping', '-n', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: capture output, discard error messages, do not show window
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, creationflags=0x08000000)
# 0x0800000 is a windows-only Popen flag to specify that a new process will not create a window.
# On Python 3.7+, you can use a subprocess constant:
# result = subprocess.run(command, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
# On windows 7+, ping returns 0 (ok) when host is not reachable; to be sure host is responding,
# we search the text "TTL=" on the command output. If it's there, the ping really had a response.
return result.returncode == 0 and b'TTL=' in result.stdout
else:
command = ['ping', '-c', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: discard output and error messages
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return result.returncode == 0
Feel free to use it as you will.
#!/usr/bin/python3
import subprocess as sp
def ipcheck():
status,result = sp.getstatusoutput("ping -c1 -w2 " + str(pop))
if status == 0:
print("System " + str(pop) + " is UP !")
else:
print("System " + str(pop) + " is DOWN !")
pop = input("Enter the ip address: ")
ipcheck()
After looking around, I ended up writing my own ping module, which is designed to monitor large numbers of addresses, is asynchronous and doesn't use a lot of system resources. You can find it here: https://github.com/romana/multi-ping/ It's Apache licensed, so you can use it in your project in any way you see fit.
The main reasons for implementing my own are the restrictions of the other approaches:
Many of the solutions mentioned here require an exec out to a command line utility. This is quite inefficient and resource hungry if you need to monitor large numbers of IP addresses.
Others mention some older python ping modules. I looked at those and in the end, they all had some issue or the other (such as not correctly setting packet IDs) and didn't handle the ping-ing of large numbers of addresses.
I resolve this with:
def ping(self, host):
res = False
ping_param = "-n 1" if system_name().lower() == "windows" else "-c 1"
resultado = os.popen("ping " + ping_param + " " + host).read()
if "TTL=" in resultado:
res = True
return res
"TTL" is the way to know if the ping is correctly.
Saludos
Make Sure pyping is installed or install it pip install pyping
#!/usr/bin/python
import pyping
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
If your server does not support ICMP (firewall might block it), it most probably still offers a service on a TCP port. In this case, you can perform a TCP ping1 (platform independently and without installing additional python modules) like this:
import socket
def isReachable(ipOrName, port, timeout=2):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
s.connect((ipOrName, int(port)))
s.shutdown(socket.SHUT_RDWR)
return True
except:
return False
finally:
s.close()
The code is taken and only slightly modified from here.
1 A TCP ping does not really exist as a ping is performed with ICMP on ISO/OSI layer 3. A TCP ping is performed on ISO/OSI layer 4. It just tries to connect to a TCP port in the most basic way, that it is not transmitting any data, but closing the connection immediately after connecting.
#!/usr/bin/python3
import subprocess as sp
ip = "192.168.122.60"
status,result = sp.getstatusoutput("ping -c1 -w2 " + ip)
if status == 0:
print("System " + ip + " is UP !")
else:
print("System " + ip + " is DOWN !")
My reduction using ideas from answers in this post but only using the newer recommended subprocess module and python3:
import subprocess
import platform
operating_sys = platform.system()
nas = '192.168.0.10'
def ping(ip):
# ping_command = ['ping', ip, '-n', '1'] instead of ping_command = ['ping', ip, '-n 1'] for Windows
ping_command = ['ping', ip, '-n', '1'] if operating_sys == 'Windows' else ['ping', ip, '-c 1']
shell_needed = True if operating_sys == 'Windows' else False
ping_output = subprocess.run(ping_command,shell=shell_needed,stdout=subprocess.PIPE)
success = ping_output.returncode
return True if success == 0 else False
out = ping(nas)
print(out)
This script works on Windows, and should work on other OSes :
It works on Windows, Debian, and macosx, need a test on solaris.
import os
import platform
def isUp(hostname):
giveFeedback = False
if platform.system() == "Windows":
response = os.system("ping "+hostname+" -n 1")
else:
response = os.system("ping -c 1 " + hostname)
isUpBool = False
if response == 0:
if giveFeedback:
print hostname, 'is up!'
isUpBool = True
else:
if giveFeedback:
print hostname, 'is down!'
return isUpBool
print(isUp("example.com")) #Example domain
print(isUp("localhost")) #Your computer
print(isUp("invalid.example.com")) #Unresolvable hostname: https://tools.ietf.org/html/rfc6761
print(isUp("192.168.1.1")) #Pings local router
print(isUp("192.168.1.135")) #Pings a local computer - will differ for your network
I ended up finding this question regarding a similar scenario. I tried out pyping but the example given by Naveen didn't work for me in Windows under Python 2.7.
An example that worked for me is:
import pyping
response = pyping.send('Your IP')
if response['ret_code'] == 0:
print("reachable")
else:
print("unreachable")
Using Multi-ping (pip install multiPing) I made this simple code (simply copy and paste if you will!):
from multiping import MultiPing
def ping(host,n = 0):
if(n>0):
avg = 0
for i in range (n):
avg += ping(host)
avg = avg/n
# Create a MultiPing object to test hosts / addresses
mp = MultiPing([host])
# Send the pings to those addresses
mp.send()
# With a 1 second timout, wait for responses (may return sooner if all
# results are received).
responses, no_responses = mp.receive(1)
for addr, rtt in responses.items():
RTT = rtt
if no_responses:
# Sending pings once more, but just to those addresses that have not
# responded, yet.
mp.send()
responses, no_responses = mp.receive(1)
RTT = -1
return RTT
Usage:
#Getting the latency average (in seconds) of host '192.168.0.123' using 10 samples
ping('192.168.0.123',10)
If you want a single sample, the second parameter "10" can be ignored!
Hope it helps!
I needed a faster ping sweep and I didn't want to use any external libraries, so I resolved to using concurrency using built-in asyncio.
This code requires python 3.7+ and is made and tested on Linux only. It won't work on Windows but I am sure you can easily change it to work on Windows.
I ain't an expert with asyncio but I used this great article Speed Up Your Python Program With Concurrency and I came up with these lines of codes. I tried to make it as simple as possible, so most likely you will need to add more code to it to suit your needs.
It doesn't return true or false, I thought it would be more convenient just to make it print the IP that responds to a ping request. I think it is pretty fast, pinging 255 ips in nearly 10 seconds.
#!/usr/bin/python3
import asyncio
async def ping(host):
"""
Prints the hosts that respond to ping request
"""
ping_process = await asyncio.create_subprocess_shell("ping -c 1 " + host + " > /dev/null 2>&1")
await ping_process.wait()
if ping_process.returncode == 0:
print(host)
return
async def ping_all():
tasks = []
for i in range(1,255):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
await asyncio.gather(*tasks, return_exceptions = True)
asyncio.run(ping_all())
Sample output:
192.168.1.1
192.168.1.3
192.168.1.102
192.168.1.106
192.168.1.6
Note that the IPs are not in order, as the IP is printed as soon it replies, so the one that responds first gets printed first.
on linux, it's possible to create ICMP datagram (not raw) sockets without being root (or setuid or CAP_NET_RAW): https://unix.stackexchange.com/a/592914. I ended up with
$ id
uid=1000(raylu) gid=1000(raylu) [...]
$ sudo sysctl net.ipv4.ping_group_range='1000 1000'
import socket
import struct
import time
def main():
ping('192.168.1.10')
def ping(destination):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.getprotobyname('icmp'))
sock.settimeout(10.0)
start_time = time.time_ns() # python 3.7+ only
payload = struct.pack('L', start_time)
sock.sendto(encode(payload), (destination, 0))
while (time.time_ns() - start_time) // 1_000_000_000 < 10:
try:
data, source = sock.recvfrom(256)
except socket.timeout:
print('timed out')
return
message_type, message_code, check, identifier, sequence_number = struct.unpack('bbHHh', data[:8])
if source == (destination, 0) and message_type == ICMP.ECHO_REPLY and data[8:] == payload:
print((time.time_ns() - start_time) // 1_000_000, 'ms')
break
else:
print('got unexpected packet from %s:' % source[0], message_type, data[8:])
else:
print('timed out')
def encode(payload: bytes):
# calculate checksum with check set to 0
checksum = calc_checksum(icmp_header(ICMP.ECHO_REQUEST, 0, 0, 1, 1) + payload)
# craft the packet again with the checksum set
return icmp_header(ICMP.ECHO_REQUEST, 0, checksum, 1, 1) + payload
def icmp_header(message_type, message_code, check, identifier, sequence_number) -> bytes:
return struct.pack('bbHHh', message_type, message_code, check, identifier, sequence_number)
def calc_checksum(data: bytes) -> int:
'''RFC 1071'''
# code stolen from https://github.com/alessandromaggio/pythonping/blob/a59ce65a/pythonping/icmp.py#L8
'''
MIT License
Copyright (c) 2018 Alessandro Maggio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
subtotal = 0
for i in range(0, len(data)-1, 2):
subtotal += (data[i] << 8) + data[i+1]
if len(data) % 2:
subtotal += (data[len(data)-1] << 8)
while subtotal >> 16:
subtotal = (subtotal & 0xFFFF) + (subtotal >> 16)
check = ~subtotal
return ((check << 8) & 0xFF00) | ((check >> 8) & 0x00FF)
class ICMP:
ECHO_REPLY = 0
ECHO_REQUEST = 8
though many of the packages other answers have suggested here would work too
Seems simple enough, but gave me fits. I kept getting "icmp open socket operation not permitted" or else the solutions would hang up if the server was off line. If, however, what you want to know is that the server is alive and you are running a web server on that server, then curl will do the job. If you have ssh and certificates, then ssh and a simple command will suffice. Here is the code:
from easyprocess import EasyProcess # as root: pip install EasyProcess
def ping(ip):
ping="ssh %s date;exit"%(ip) # test ssh alive or
ping="curl -IL %s"%(ip) # test if http alive
response=len(EasyProcess(ping).call(timeout=2).stdout)
return response #integer 0 if no response in 2 seconds
Use this it's tested on python 2.7 and works fine it returns ping time in milliseconds if success and return False on fail.
import platform,subproccess,re
def Ping(hostname,timeout):
if platform.system() == "Windows":
command="ping "+hostname+" -n 1 -w "+str(timeout*1000)
else:
command="ping -i "+str(timeout)+" -c 1 " + hostname
proccess = subprocess.Popen(command, stdout=subprocess.PIPE)
matches=re.match('.*time=([0-9]+)ms.*', proccess.stdout.read(),re.DOTALL)
if matches:
return matches.group(1)
else:
return False
I had similar requirement so i implemented it as shown below. It is tested on Windows 64 bit and Linux.
import subprocess
def systemCommand(Command):
Output = ""
Error = ""
try:
Output = subprocess.check_output(Command,stderr = subprocess.STDOUT,shell='True')
except subprocess.CalledProcessError as e:
#Invalid command raises this exception
Error = e.output
if Output:
Stdout = Output.split("\n")
else:
Stdout = []
if Error:
Stderr = Error.split("\n")
else:
Stderr = []
return (Stdout,Stderr)
#in main
Host = "ip to ping"
NoOfPackets = 2
Timeout = 5000 #in milliseconds
#Command for windows
Command = 'ping -n {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
#Command for linux
#Command = 'ping -c {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
Stdout,Stderr = systemCommand(Command)
if Stdout:
print("Host [{}] is reachable.".format(Host))
else:
print("Host [{}] is unreachable.".format(Host))
When IP is not reachable subprocess.check_output() raises an exception. Extra verification can be done by extracting information from output line 'Packets: Sent = 2, Received = 2, Lost = 0 (0% loss)'.
WINDOWS ONLY - Can't believe no-ones cracked open Win32_PingStatus
Using a simple WMI query we return an object full of really detailed info for free
import wmi
# new WMI object
c = wmi.WMI()
# here is where the ping actually is triggered
x = c.Win32_PingStatus(Address='google.com')
# how big is this thing? - 1 element
print 'length x: ' ,len(x)
#lets look at the object 'WMI Object:\n'
print x
#print out the whole returned object
# only x[0] element has values in it
print '\nPrint Whole Object - can directly reference the field names:\n'
for i in x:
print i
#just a single field in the object - Method 1
print 'Method 1 ( i is actually x[0] ) :'
for i in x:
print 'Response:\t', i.ResponseTime, 'ms'
print 'TTL:\t', i.TimeToLive
#or better yet directly access the field you want
print '\npinged ', x[0].ProtocolAddress, ' and got reply in ', x[0].ResponseTime, 'ms'
sample output
Here's a solution using Python's subprocess module and the ping CLI tool provided by the underlying OS. Tested on Windows and Linux. Support setting a network timeout. Doesn't need root privileges (at least on Windows and Linux).
import platform
import subprocess
def ping(host, network_timeout=3):
"""Send a ping packet to the specified host, using the system "ping" command."""
args = [
'ping'
]
platform_os = platform.system().lower()
if platform_os == 'windows':
args.extend(['-n', '1'])
args.extend(['-w', str(network_timeout * 1000)])
elif platform_os in ('linux', 'darwin'):
args.extend(['-c', '1'])
args.extend(['-W', str(network_timeout)])
else:
raise NotImplemented('Unsupported OS: {}'.format(platform_os))
args.append(host)
try:
if platform_os == 'windows':
output = subprocess.run(args, check=True, universal_newlines=True).stdout
if output and 'TTL' not in output:
return False
else:
subprocess.run(args, check=True)
return True
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
return False
My take borrowing from other answers. Attempt to simplify and minimize queries.
import platform, os
def ping(host):
result = os.popen(' '.join(("ping", ping.param, host))).read()
return 'ttl=' in result.lower()
ping.param = "-n 1" if platform.system().lower() == "windows" else "-c 1"
EDIT: ignoring case in return as per comment by Olivier B.
import os #to get clear screen
import subprocess as sp #to get system ping
os.system("clear") #clear screen
print('Wait or Press Ctrl+Z to Terminate\n') #notice to terminate or wait
for i in range(255): #0 to 255 loop
ip='192.168.1.'+str(i) #concatenating str and int
s,r=sp.getstatusoutput("ping -c1 -w2 " + ip) #ping and store status in s
if s==0: #if status is 0 equal to pass
print(ip+" is UP ✓ ") #output
else: #if status is not 0 equal to fail
pass #skip and try next ip from loop
Ping them all in windows or linux, return a sorted list. This is a hybrid/fix from the responses #Ahmed Essam and #Arno.
import asyncio
import re
import platform
isWindows = platform.system()
async def ping(host):
cmd = 'ping {} {} 1'.format(host, '-n' if isWindows else '-c')
ping_proc = \
await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await ping_proc.communicate()
outstr = stdout.decode()
if ping_proc.returncode == 0:
delay = int(re.search(r'(?:time=)([\d]*)', outstr).group(1)) if 'time=' in outstr else -1
if delay >= 0:
# print('{} {}ms'.format(host, delay))
return [host, delay]
return [host, None]
async def ping_all():
tasks = []
for i in range(1, 256):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
retList = await asyncio.gather(*tasks, return_exceptions=True)
retList = [x for x in retList if x[1] is not None]
retList.sort(key=lambda x: int(x[0].split('.')[-1]))
return retList
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
pingRet = loop.run_until_complete(ping_all())
for ip, d in pingRet:
print('{:<16s} {}ms'.format(ip, d))
My own method that combines several answers above:
def ping(host, show_log=False, package_count=1):
ping.param = "-n" if platform.system().lower() == 'windows' else "-c"
result = subprocess.run(['ping', ping.param, str(package_count), host],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output = result.stdout
if show_log:
print('return code: ', result.returncode)
print(output.decode("utf-8"))
return result.returncode == 0 and (b'TTL=' in output or b'ttl=' in output)
Tested on OSX Monterey.

Categories