ping multiple Ips with python

darrell dgallion1 at yahoo.com
Fri Jan 3 22:07:38 EST 2003


Multiple ping sounded like fun.
So here's a quick mod to some ping code I found.

--Darrell Gallion


#!/usr/bin/env python

# Derived from ping.c distributed in Linux's netkit. That code is
# copyright (c) 1989 by The Regents of the University of California.
# That code is in turn derived from code written by Mike Muuss of the
# US Army Ballistic Research Laboratory in December, 1983 and
# placed in the public domain. They have my thanks.

# Bugs are naturally mine. I'd be glad to hear about them. There are
# certainly word-size dependenceies here.

# Copyright (c) Matthew Dixon Cowles, <http://www.visi.com/~mdc/>.
# Distributable under the terms of the GNU General Public License
# version 2. Provided with no warranties of any sort.

# Note that ICMP messages can only be sent from processes running
# as root.

# Revision history:
#
# November 22, 1997
# Initial hack. Doesn't do much, but rather than try to guess
# what features I (or others) will want in the future, I've only
# put in what I need now.
#
# December 16, 1997
# For some reason, the checksum bytes are in the wrong order when
# this is run under Solaris 2.X for SPARC but it works right under
# Linux x86. Since I don't know just what's wrong, I'll swap the
# bytes always and then do an htons().
#
# December 4, 2000
# Changed the struct.pack() calls to pack the checksum and ID as
# unsigned. My thanks to Jerome Poincheval for the fix.
#
# Jan 3, 2003
# Added Pinger class to handle multiple ping dest
# Darrell Gallion
#

import os
from socket import *
import struct
import select
import time
import sys

# From /usr/include/linux/icmp.h; your milage may vary.
ICMP_ECHO_REQUEST=8 # Seems to be the same on Solaris.
myID=os.getpid() & 0xFFFF

# I'm not too confident that this is right but testing seems
# to suggest that it gives the same answers as in_cksum in ping.c
def checksum(str):
  sum=0
  countTo=(len(str)/2)*2
  count=0
  while count<countTo:
    thisVal=ord(str[count+1])*256+ord(str[count])
    sum=sum+thisVal
    sum=sum & 0xffffffff # Necessary?
    count=count+2

  if countTo<len(str):
    sum=sum+ord(str[len(str)-1])
    sum=sum & 0xffffffff # Necessary?

  sum=(sum >> 16) + (sum & 0xffff)
  sum=sum+(sum >> 16)
  answer=~sum
  answer=answer & 0xffff

  # Swap bytes. Bugger me if I know why.
  answer=answer >> 8 | (answer << 8 & 0xff00)
  return answer


class Pinger:
    def __init__(self, *dest):
        self.results={}
        icmp=getprotobyname("icmp")
        self.soc=socket(AF_INET,SOCK_RAW,icmp)
    
    def receivePings(self,timeout):
        timeLeft=timeout
        while 1:
            startedSelect=time.time()
            whatReady=select.select([self.soc],[],[],timeLeft)
            howLongInSelect=(time.time()-startedSelect)
            if whatReady[0]==[]: # Timeout
                return 
            timeReceived=time.time()
            recPacket,addr= self.soc.recvfrom(1024)
            icmpHeader=recPacket[20:28]
            
type,code,checksum,packetID,sequence=struct.unpack("bbHHh",icmpHeader)
            if self.destDict.has_key(packetID):
                bytesInDouble=struct.calcsize("d")
                
timeSent=struct.unpack("d",recPacket[28:28+bytesInDouble])[0]
                dT = timeReceived-timeSent
                self.results[self.destDict[packetID]]=dT
#                print self.destDict[packetID], dT
                del self.destDict[packetID]
                if len(self.destDict)==0:
                    return
                
            timeLeft=timeLeft-howLongInSelect
            if timeLeft<=0:
                return 
    
    def sendPings(self):
        for ID, dest in self.destDict.items():
            # Header is type (8), code (8), checksum (16), id (16), sequence 
(16)
            myChecksum=0
            # Make a dummy heder with a 0 checksum.
            header=struct.pack("bbHHh",ICMP_ECHO_REQUEST,0,myChecksum, ID,1)
            bytesInDouble=struct.calcsize("d")
            data=(192-bytesInDouble) * "Q"
            data=struct.pack("d",time.time())+data
            # Calculate the checksum on the data and the dummy header.
            myChecksum=checksum(header+data)
            # Now that we have the right checksum, we put that in. It's just 
easier
            # to make up a new header than to stuff it into the dummy.
            
header=struct.pack("bbHHh",ICMP_ECHO_REQUEST,0,htons(myChecksum), ID,1)
            packet=header+data
            self.soc.sendto(packet,(dest,1)) # Don't know about the 1
    
    def ping(self, destAddr,timeout=10):
        # Returns either the delay (in seconds) or none on timeout.
        dest=[]
        for n in destAddr:
            dest.append(gethostbyname(n))
        self.destDict={}
        cnt=3 # Started at 3 for no good reason
        for d in destAddr:
            self.destDict[cnt]=d
            cnt+=1
            
        self.sendPings()
        self.receivePings(timeout)
        self.soc.close()
        return self

def main():
    if len(sys.argv)<2:
        print "Usage: %s hostname" % os.path.basename(sys.argv[0])
        sys.exit(1)

    print Pinger().ping(sys.argv[1:]).results
    return None

if __name__=='__main__':
  main()
  sys.exit(0)





More information about the Python-list mailing list