Pong v3, un mass pingueur python gpl

Contenu du snippet

"Pong" est utile pour pinguer des centaines de machines rapidement avec une syntaxe courte...
Pong est multithreads, ce qui lui permet de pinguer plusieurs machines en même temps.

Comment ca marche ? Basiquement, comme ping :
pong 172.16.0.1

Plus spécifiquement :
pong 172.16.50,52,54,60.1-25
cette commande ping 100 machines

autre exemple : pong 172.16.1,2.1-5:172.20.1,2,3.1-25:192.168.1.1-10

Ca donne quoi sur une console ?

mymachine% pong 172.16.52.1-10
IP MAC Status Times (ms)
172.16.52.1 0F:14:2F:3F:37:F0 Up 0.247 1.988
172.16.52.2 Down
172.16.52.3 Down
172.16.52.4 Down
172.16.52.5 00:1F:22:FE:AA:FA Up 0.263 0.868
172.16.52.6 00:14:2F:3F:46:F9 Up 0.220 0.730
172.16.52.7 00:1F:22:3F:46:F9 Up 0.226 4.058
172.16.52.8 00:14:2F:3F:46:7F Up 0.238 3.742
172.16.52.9 00:1F:22:3F:68:FF Up 0.256 2.980
172.16.52.10 00:1F:2F:3F:45:5F Up 0.250 1.333

Pong Report : 10 IPs Ponged in : 0h 0m 2s 0909ms
7 Hosts Up
3 Hosts Down
0 Hosts Weird

Pong accepte plein d'options d'affichage de sorte à contraindre la sortie ecran à ce que l'on souhaite ...
Utile pour créer des logs ...

Pong V3.00 est un soft sous licence GPLv3
Développé/Fonctionne sous Python 2.5.1

Paquet DEB pour Debian ou Ubuntu :
http://www.kik-it.com/downloads/PYTHON_STUFF/Pong.deb

Source / Exemple :


#!/usr/bin/python
# -*- coding: utf_8 -*-

u"""
    program : Pong V 3.0
    file    : pong.py
    author  : Frédérick Lemasson < djassper [at] gmail [dot] com >
    licence : GPL v3.0
    created : 2007-08-27
    revised : 2007-09-03
    purpose : Ping lots of IPs (V4) using a single command line and prints a report
    exemple : pong 172.16.1,2.1-5:172.20.1,2,3.1-25:192.168.1.1-10

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details :

            http://www.gnu.org/licenses
            http://www.gnu.org/licenses/gpl-3.0.html
            http://www.gnu.org/philosophy/

"""

from __future__ import with_statement
import os
#import re
import time
import sys
from threading import Thread
from optparse import OptionParser
pong=sys.modules['__main__']

usage = u"""
        pong [options] IPCode

IPCode is translated to IPs following the rules :
    
    Special characters you can use in octets (only one per octet) :
        "-" means range, Exemple : 1-5 means 1,2,3,4,5
        "*" means range [0-255]
        "," means list,  Exemple : 1,3,12 means 1,3,12 

    You can use ":" between IPCodes :         
        IPCodes exemples : 172.16.1,2.1-5:172.20.1,2,3.1-25
                           192.168.1.*
                           10.1.1.100 

  Pong Copyright (C) 2007 Frédérick Lemasson - France
  This program comes with ABSOLUTELY NO WARRANTY.
  This is GPL free software, and you are welcome to redistribute it under 
  certain conditions. If you Improve/Modify/Debug Pong, 
  you ["must" AND "will be happy to"] send me an email.
  for details type "pong --licence".

"""

parser = OptionParser(usage)
#Simple Options
parser.add_option("-u", "--HideUp", dest="HideUp", action="store_true", default=False, help="Hide Hosts Up")
parser.add_option("-d", "--HideDown", dest="HideDown", action="store_true", default=False, help="Hide Hosts Down")
parser.add_option("-w", "--HideWeird", dest="HideWeird", action="store_true", default=False, help="Hide Hosts Weird")
parser.add_option("-i", "--HideIP", dest="HideIP", action="store_true", default=False, help="Hide IPs from report")
parser.add_option("-s", "--HideStatus", dest="HideStatus", action="store_true", default=False, help="Hide Status from report")
parser.add_option("-m", "--HideMAC", dest="HideMAC", action="store_true", default=False, help="Hide MACs from report")
parser.add_option("-t", "--HideTimes", dest="HideTimes", action="store_true", default=False, help="Hide Times from report")
parser.add_option("-c", "--HideHeaders", dest="HideHeaders", action="store_true", default=False, help="Don't show the Columns Headers")
parser.add_option("-r", "--HideReport", dest="HideReport", action="store_true", default=False, help="Don't show the report")
parser.add_option("-b", "--Beep", dest="Beep", action="store_true", default=False, help="Beeps when a host is either Down or Weird")
parser.add_option("--licence", dest="licence", action="store_true", default=False, help="Prints Pong Licence informations")
#Parameter Options
parser.add_option("-e", "--Exclude", dest="Exclude", metavar="IPCode", help="Exclude IPs from ping list")
parser.add_option("-f", "--InputFile", dest="InputFile", help="Specify a file containing IPCodes to ping, one IPCode per line")
parser.add_option("-R", "--Report", dest="Report", help="Build/Update a long term Report")
parser.add_option("-L", "--Limit", type="int", dest="Limit", help="Sets the long term Report occurences limit")
parser.add_option("-W", "--Wait", type="int", dest="Wait", default=1, help="Time to wait for a response, in seconds, default is 1s")

(options, args) = parser.parse_args()

if options.licence:
    print usage,pong.__doc__
    sys.exit()

if len(args) != 1 and not options.InputFile:
        parser.error("incorrect number of arguments")

### Functions ###

class NDict(dict):
    """ Customized dict, don't raise KeyError exception, return None instead """
    def __getitem__(self, key):
        if self.has_key(key):
            return dict.__getitem__(self, key)
        else:
            return ""

class Pong(Thread):
    """ Sends pings in parallel using Thread module """
    def __init__ (self,ip):
        Thread.__init__(self)
        self.ip = ip
        self.status = -1
        self.times= ""
    def run(self):
        ping = os.popen("ping -q -c2 -W"+str(options.Wait)+" "+self.ip,"r")
        while 1:
            line = ping.readline()
            if not line: break
            if "," in line and self.status==-1:
                Result = int(line.split(",")[1].strip().split()[0])
                if Result in [0,1,2]: self.status = Result
            if "=" in line and self.times=="":
                Result = line.split("=")[1].strip().split("/")
                self.times = str(Result[0]) + " " +str(Result[2])

def Beep():
    print >> sys.stderr, "\a",

def TimeFrom(StartTime):
    """ Returns Time elapsed between now and given time (returns in format : h m s ms)"""
    StopTime=time.time()
    Took=StopTime - StartTime
    Foo=time.gmtime(Took)
    return str(Foo[3])+"h "+str(Foo[4])+"m "+str(Foo[5])+"s "+str(Took).split(".")[1][:4]+"ms"

def Range2List(TheRange):
    """ Turns octet range user input in python list"""
    TheRange=TheRange.split("-")
    return range(int(TheRange[0]),int(TheRange[1])+1)

def List2List(TheList):
    """ Turns octet list user input in python list"""
    TheCleanList=[]
    for item in TheList.split(","):
        TheCleanList.append(int(item))
    return TheCleanList

def ClearFile(TheFile):
    with open(TheFile,"w") as f:
        f.write("")

def ReadFile(TheFile):
    """ Returns complete text file"""
    with open(TheFile,"rb") as f:
        return f.read()

def WriteFile(TheFile,Content):
    with open(TheFile,"w") as f:
        f.write(Content)

def AppendFile(TheFile,Content):
    with open(TheFile,"a") as f:
        f.write(Content)

def Read2Dic(TheFile):
    key=0
    TheDic={}
    for line in file(TheFile):
        key += 1
        TheDic[str(key)] = line
    return TheDic

def Report2Dic(TheFile):
    TheDic=NDict()
    for line in file(TheFile):
        Data=line.split()
        TheDic[str(Data[0])] = str(" ".join(Data[1:]))
    return TheDic

def Dic2Report(TheDic, TheReport):
    sortedkeys = TheDic.keys()
    sortedkeys.sort()
    #NatSort(sortedkeys)
    with open(TheReport,"a") as f:
	    for k in sortedkeys:
               f.write(k+" "+TheDic[k]+"\n")

def GetIPsMAC():
    """ Populate global Dict MACs which contains IP as Key and MAC as Value"""
    global MACs
    arptable = ReadFile("/proc/net/arp")
    for line in arptable.split("\n"):
        if not line: break
        Item=line.split()
        MACs[Item[0]]=Item[3]

def IPCode2List(TheIPCodes):
    """ Used in exclude mode to turn IPCodes into a IPs List"""
    IPCodes=TheIPCodes.split(":")
    TheList=[]
    for IPCode in IPCodes:
        if IPCode=="":continue
        Octets=IPCode.split(".")

        for Current in range(len(Octets)):   
            if Octets[Current]=="*" : Octets[Current]="0-255" #Broadcast included but ping will zap it, could be handled though
            if Octets[Current].find("-")!=-1:           #Octet Codes for a range
                Octets[Current]=Range2List(Octets[Current])
            elif  Octets[Current].find(",")!=-1:        #Octet codes for a list
                Octets[Current]=List2List(Octets[Current])
            else:                                       #Octet codes for himself
                Octets[Current]=[int(Octets[Current])]
        
        for Octet0 in Octets[0]:
            for Octet1 in Octets[1]:
                for Octet2 in Octets[2]:
                    for Octet3 in Octets[3]:
                        TheList.append(str(Octet0)+"."+str(Octet1)+"."+str(Octet2)+"."+str(Octet3))
    return TheList

### Variables ###

StartTime=time.time()
report = ("Down","Weird","Up")
PingsUp=0
PingsDown=0
PingsWeird=0
MACs=NDict()
Data=NDict()

if options.Exclude: 
    ExclusionList=IPCode2List(options.Exclude)
else:
    ExclusionList=[]

if options.InputFile:
    IPCodes=ReadFile(options.InputFile).replace("\n",":").split(":")
else:
    #User input exemple : 172.16.50,52,60.1-25:172.20.150,154.1-20
    IPCodes=args[0].split(":")

if options.Report:
    Report=NDict()
    if os.path.exists(options.Report):
        Report=Report2Dic(options.Report)
    else:
        ClearFile(options.Report)

### Code ###

if not options.HideHeaders:
    Headers=""
    Headers+="IP".ljust(16)         if not options.HideIP     else ""
    Headers+="MAC".ljust(19)        if not options.HideMAC    else ""
    Headers+="Status".ljust(8)      if not options.HideStatus else ""
    Headers+="Times (ms)".ljust(18) if not options.HideTimes  else ""
    print Headers

for IPCode in IPCodes:
    if IPCode=="":continue

    Octets=IPCode.split(".")

    for Current in range(len(Octets)):   
        if Octets[Current]=="*" : Octets[Current]="0-255" #Broadcast included but ping will zap it, could be handled though
        if Octets[Current].find("-")!=-1:           #Octet Codes for a range
            Octets[Current]=Range2List(Octets[Current])
        elif  Octets[Current].find(",")!=-1:        #Octet codes for a list
            Octets[Current]=List2List(Octets[Current])
        else:                                       #Octet codes for himself
            Octets[Current]=[int(Octets[Current])]
    
    for Octet0 in Octets[0]:
        for Octet1 in Octets[1]:
            for Octet2 in Octets[2]:
                pinglist = []
                Data=NDict()
                #Build complete IPs and send Pings Threads
                for Octet3 in Octets[3]:
                    IP = str(Octet0)+"."+str(Octet1)+"."+str(Octet2)+"."+str(Octet3)
                    if IP in ExclusionList: continue
                    current = Pong(IP)
                    pinglist.append(current)
                    current.start()

                #Join Pings Threads responses / define their status
                for pinged in pinglist:
                    pinged.join()

                    #Set Counters and what to print
                    if pinged.status==0:
                        PingsDown += 1
                        if options.Beep:Beep()
                        if options.HideDown:continue
                    elif pinged.status==1:
                        PingsWeird += 1
                        if options.Beep:Beep()
                        if options.HideWeird:continue
                    elif pinged.status==2:
                        PingsUp += 1
                        if options.HideUp:continue
                    #Populate IP Datas on Status
                    Data[pinged.ip]={}
                    Data[pinged.ip]["Status"]=report[pinged.status]
                    Data[pinged.ip]["Times"]=pinged.times
                    
                #Pings Just returned, Populate MACs Dict with fresh arp table
                if not options.HideMAC:GetIPsMAC()
                IPs=Data.keys()
                #ReLoop in last Octet and print results
                for Octet3 in Octets[3]:
                    IP = str(Octet0)+"."+str(Octet1)+"."+str(Octet2)+"."+str(Octet3)
                    if IP in IPs:
                        if not options.HideMAC:Data[IP]["Mac"]=MACs[IP] if MACs[IP]!="00:00:00:00:00:00" else ""
                        Line=""
                        Line+=IP.ljust(16)                 if not options.HideIP       else ""
                        Line+=Data[IP]["Mac"].ljust(19)    if not options.HideMAC      else ""                       
                        Line+=Data[IP]["Status"].ljust(8)  if not options.HideStatus   else ""
                        Line+=Data[IP]["Times"].ljust(18)  if not options.HideTimes    else ""

                        print Line
                        if options.Report:
                            Infos=Line.split()
                            Report[str(Infos[0])]+=" ".join(Infos[1:])+"/"
                            #Report[str(Infos[0])]=Report[str(Infos[0])][0:-1]
                            if options.Limit:
                                #keeps the last options.Limits occurences
                                occurences=Report[str(Infos[0])].split("/")
                                if len(occurences)-1>options.Limit:
                                    Report[str(Infos[0])]="/".join(occurences[-options.Limit-1:])

    
if not options.HideReport:
    print ""
    print "Pong Report : "+str(PingsUp+PingsDown+PingsWeird).rjust(8) +" IPs Ponged in :",TimeFrom(StartTime)
    print "              "+str(PingsUp).rjust(8)+" Hosts Up"
    print "              "+str(PingsDown).rjust(8)+" Hosts Down"
    print "              "+str(PingsWeird).rjust(8)+" Hosts Weird"
    print ""

if options.Report:
    ClearFile(options.Report)
    Dic2Report(Report, options.Report)

Conclusion :


Si quelqun se sent de faire en sorte que Pong marche sous Windows (pas compliqué il n'y a que la syntaxe/traitement du ping à changer) j'en serai flaté ...

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.