#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Name:        scanner.py
# Purpose:     Un scanner de port (portable naturellement)
#
# Author:      Kototama
# Mail:        kototama-code @ altern . org
#
# Created:     2003/07/12
# Updated:     jeu aoû  5 20:19:51 CEST 2004
# RCS-ID:      $Id: scanner.py $
# Copyright:   (c) 2003
# Licence:     GNU public license.
# Notes:       Use pychecker it rulez :)
#-----------------------------------------------------------------------------


##

##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 2

##of the License, or (at your option) 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.

##

##You should have received a copy of the GNU General Public License

##along with this program; if not, write to the Free Software

##Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.



import threading
import socket
import sys

ver = sys.version_info
if (ver[0] < 2 or (ver[0] == 2 and ver[1] < 3)):
    print 'Update your version of python before running the scanner.'
    sys.exit(-1)

try:
    from Tkinter import *
    from ScrolledText import *
    from tkFileDialog import *
except:
    print 'Error while loading Tk library.'
    print 'Install it before using the scanner.'
    sys.exit(-1)



class scanner(Frame):
    scanned = 0
    ip = None
    file = None
    portbegin = None
    portend = None
    logtext = None

    def __init__(self, parent=None):
        """Constructeur : on créer l'interface graphique"""
        Frame.__init__(self, parent)
        self.pack()

        self.scanned = 0
        self.ip = None
        self.file = None
        self.portbegin = None
        self.portend = None
        self.logtext = None

        f1 = Frame(self)
        f1.pack(expand=YES, fill=X)

        f12 = Frame(self)
        f12.pack(expand=YES, fill=X)

        f2 = Frame(self)
        f2.pack(expand=YES, fill=X)

        f3 = Frame(self)
        f3.pack(expand=YES, fill=X)

        f4 = Frame(self)
        f4.pack(expand=YES, fill=BOTH)



        iplabel = Label(f1, text='I.P / Host :')
        iplabel.pack(side=LEFT)

        self.ip = StringVar()
        self.ip.set('127.0.0.1')
        ipentry = Entry(f1, textvar=self.ip)
        ipentry.pack(side=LEFT)

        Label(f2, text='Ports :').pack(side=LEFT)


        filelabel = Label(f12, text='From file :')
        filelabel.pack(side=LEFT)

        self.file = StringVar()
        fileentry = Entry(f12, textvar=self.file);
        fileentry.pack(side=LEFT)

        filebutton = Button(f12, text='Load file', command=lambda: self.loadFile())
        filebutton.pack(side=LEFT)

        self.portbegin = IntVar()
        self.portbegin.set(1)
        portbeginentry = Entry(f2, textvar=self.portbegin)
        portbeginentry.pack(side=LEFT)

        self.portend = IntVar()
        self.portend.set(1024)
        portendentry = Entry(f2, textvar=self.portend)
        portendentry.pack(side=LEFT)

        scanbutton = Button(f3, text='Start scan', command=lambda: self.scan())
        scanbutton.pack(side=LEFT)

        logbutton = Button(f3, text='Save to file', command=lambda: self.log())
        logbutton.pack(side=RIGHT)

        self.logtext = ScrolledText(f4)
        self.logtext.pack(side=LEFT)

    def loadFile(self):
        """Chargement d'un fichier contenant une liste d'I.P"""
        self.file.set(askopenfilename()) 

    def scan(self):
        """ 
            On lance un thread pour le scan pour pouvoir utiliser
            l'interface graphique pendant le scan.
        """
        if self.scanned:
            return
        thread = threading.Thread(None, self.launchscan)
        thread.start()

    def launchscan(self):
        """On récupère l'IP ou les IPS et on scanne"""
        ips = []

        if(self.file.get() == ""):
            # s'il n'y a pas d'IP dans le champs on récupère les IPs à partir
            # du fichier
            ips.append(self.ip.get()+"\n")
        else:
            try:
                f = open(self.file.get())
                ips = f.readlines()
            except:
                self.logtext.insert(END,"I can't open "+self.file.get()+"\n")

        for ip in ips:
            self.opened = []	
            try:
                # on regarde si on peut se connecter à la machine cible
                # en résolvant son nom...
                self.host = socket.gethostbyaddr(ip[:-1])
            except:
                self.logtext.insert(END, str(ip[:-1])+" : can't connect.\n")
            else:
                log = "Scanning %s (%s) ...\n\n" % (ip[:-1], self.host[0])
                self.logtext.insert(END, log)
                print 'Scanning ip %s' % (ip)
                self.scanhost(ip)

    def scanhost(self, ip=None):
        """On scanne les ports du pc avec un thread par port"""
        self.scanned = 1
        threads = []
        for port in range(self.portbegin.get(), self.portend.get()+1):
            thread = threading.Thread(None, self.scanport, None, (ip[:-1], port) )
            threads.append(thread)
            thread.start()

        # on attend que les threads se terminent
        for mythread in threads:
            mythread.join()

        self.opened.sort()
        for port in self.opened:
            log = "\t%5d => open\n" % (port)
            self.logtext.insert(END, log)

        self.logtext.insert(END,"\nScan finished\n\n")
        self.opened = []
        self.scanned = 0

    def scanport(self, ip, port):
        """On essaye de se connecter Ã  un port pour savoir s'il est ouvert"""
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print 'Scanning port %d' % port
        s.settimeout(2)
        try:
            s.connect((ip, port))
        except:
            pass
        else:
            self.opened.append(port)
            s.close()

    def log(self):
        """On enregistre ce qu'il y a dans la fenêtre dans un fichier"""
        try:
            f = asksaveasfile()
            all = self.logtext.get('1.0', END+'-1c')
            f.write(all)
            f.close()
        except:
            pass

if __name__ == '__main__':
    scanner().mainloop()
