• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

Personal Project Python: Nmap -> mysql

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.

Stratus_ss

Overclockix Snake Charming Senior, Alt OS Content
Joined
Jan 24, 2006
Location
South Dakota
So I am using this thread mostly as my own way of tracking my progress.
The idea is that I am developing a python program that gets the input from Nmap and stores it in a mysql database.

Currently my table layout is as follows
Code:
-- phpMyAdmin SQL Dump
-- version 3.3.10deb1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Sep 23, 2011 at 09:47 PM
-- Server version: 5.1.54
-- PHP Version: 5.3.5-1ubuntu7.2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `nmap`
--

-- --------------------------------------------------------

--
-- Table structure for table `Computer_Info`
--

CREATE TABLE IF NOT EXISTS `Computer_Info` (
  `Computer_ID` int(11) NOT NULL AUTO_INCREMENT,
  `DNS_Name` varchar(50) NOT NULL,
  `Computer_IP_Address` varchar(15) NOT NULL,
  `OS_ID` int(11) NOT NULL,
  PRIMARY KEY (`Computer_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `Computer_Info`
--


-- --------------------------------------------------------

--
-- Table structure for table `Computer_Ports`
--

CREATE TABLE IF NOT EXISTS `Computer_Ports` (
  `Computer_ID` int(11) NOT NULL,
  `Port_ID` int(11) NOT NULL,
  PRIMARY KEY (`Computer_ID`,`Port_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Dumping data for table `Computer_Ports`
--


-- --------------------------------------------------------

--
-- Table structure for table `OS_Table`
--

CREATE TABLE IF NOT EXISTS `OS_Table` (
  `OS_ID` int(11) NOT NULL AUTO_INCREMENT,
  `OS_Name` varchar(100) NOT NULL,
  PRIMARY KEY (`OS_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `OS_Table`
--


-- --------------------------------------------------------

--
-- Table structure for table `Ports_Table`
--

CREATE TABLE IF NOT EXISTS `Ports_Table` (
  `Port_ID` int(11) NOT NULL AUTO_INCREMENT,
  `Port_Number` int(11) NOT NULL,
  PRIMARY KEY (`Port_Number`),
  UNIQUE KEY `Port_ID` (`Port_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `Ports_Table`
--


-- --------------------------------------------------------

--
-- Table structure for table `Port_Description`
--

CREATE TABLE IF NOT EXISTS `Port_Description` (
  `Port_Number` varchar(50) NOT NULL,
  `Port_Description` varchar(100) NOT NULL,
  `Port_Protocol` varchar(3) NOT NULL,
  PRIMARY KEY (`Port_Number`),
  UNIQUE KEY `Port_Number` (`Port_Number`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


--
-- Dumping data for table `Port_Description`
--

Currently you have to edit the script to tell nmap where to scan. Eventually it will take user input. The script which puts the information into mysql is as follows

Code:
#!/usr/bin/python
#This script is being designed to cleanup an NMAP produced text file and insert it into mysql

import sys, os
import re
import MySQLdb
from BeautifulSoup import BeautifulSoup, NavigableString


#####Global variables

last_line = '---'  #if you reach this line, treat previous lines as a single block
scratch_file = "sit_new"
#nmap_output is the file which nmap will be piped to
nmap_output = "SIT_nmap"

#When the flag is set to 0 the script will begin to read
#When the flag is set to 1, the script knows that this is being designated as the last line
flag = 1

# Open the connection to the database
database_connection = MySQLdb.connect('192.168.89.22', 'root', '', 'nmap');
cursor = database_connection.cursor()
##########################################################################
def createNmap():
    
    
    #Run the nmap command with the option to querry the host OS
    #os.system("sudo nmap -O 192.168.88.0/24 > '%s'" % str(nmap_output))    
    nmap_unformatted = open(nmap_output, "r").readlines()
    #Words to exclude
    word1 = "up"
    word3 = "Starting"
    word4 = "done"
    word5 = "Not"
    word6 = "MAC"
    word7 = "Device"
    word8 = "Network"
    word9 = "detection"

#Here I am redirecting standard out to the scratch file
#So that the info can be more easily managed
    old_stdout = sys.stdout
    sys.stdout = open(scratch_file, "w")
    for line in nmap_unformatted:
        if word1 not in line and word3 not in line and word5 not in line and word6 not in line and word7 not in line and word8 not in line and word9 not in line:
     #replace the blank lines with dashes so that they are easier to parse
            if line.isspace():
                print "---"
            else:
                print line.strip()
    #Put the stardard out back to normal
    sys.stdout = old_stdout
##########################################################################    
def parse_dns():
    text = open(scratch_file, "r").readlines()
    #filter out the hostname expecting user.company.com
    hostname = re.compile(r'[\w\-][\w\-\.]+.com')
    #filter out the IP, expecting a 192 address
    ip = re.compile(r'192.\d+.\d+.\d+')
    
    computer_id = 1
    #go through the text line by line
    ip_address_list = []
    host_name_list = []
    for word in text:        
        find_ip = ip.findall(word)
        find_ip = " ".join(find_ip)   
        find_hostname = hostname.findall(word)
        find_hostname = " ".join(find_hostname)
        #if the hostname and the IP are blank pass
        if str(find_hostname) == "" and find_ip == "":
            pass
        #If the hostname is not in dns but it has an ip, insert the information into the ip table    
        elif find_hostname == "" and find_ip != "":
            computer_id +=1 
            print "inserting :", find_ip         
            ip_address_list.append(find_ip)
            host_name_list.append("Not Available")
        #This statement assumes that both the dns name and ip are parsed properly and it adds this information to the proper table
        else:
            print "inserting :", find_hostname
            host_name_list.append(find_hostname)
            ip_address_list.append(find_ip)
            computer_id +=1
    
    counter = 0
    #Use the length of the ip_address_list to determine the number of loops to run to add to database
    while counter < len(ip_address_list):
        ID = counter + 1
        print "Adding OS ID: ", ID, " IP Address: ", ip_address_list[counter], " and Host Name: ", host_name_list[counter]
        cursor.execute("INSERT ignore INTO Computer_Info(Computer_ID, DNS_Name,Computer_IP_Address,OS_ID) values('%s','%s','%s', '%s')" % (ID, host_name_list[counter], ip_address_list[counter], ID))
        cursor.execute("INSERT ignore INTO Computer_Ports(Computer_ID, Port_ID) values('%s', '%s')" % (ID, ID))
        counter +=1
        
#########################################################################    
def parse_ports():
    
        ###############Parse known ports from the IANA list ####################
    #open the xml file for reading
    ports_xml = open("port_numbers.xml", "r")
    search_xml = BeautifulSoup(ports_xml) 

    #This tells beautiful soup to pull out only the name tag 
    search_unassigned_numbers = search_xml.findAll('record')
    #The file contains stuff we dont want (unassined and reserved ports)
    #This list contains the known ports that we want
    filtered_entries = []

    #append the appropriate ports to the filtered_entries list
    for entries in search_unassigned_numbers:
        entries = str(entries)
        if "Unassigned" in entries or "Reserved" in entries:
            pass
        else:
            filtered_entries.append(entries)

    #Turn the list into text so that Beautiful soup can use it
    filtered_entries = "".join([x for x in filtered_entries])

    #Change the soup tags so that it is searching the filtered entries
    search_xml = BeautifulSoup(filtered_entries)
    search_port = search_xml.findAll('record')

    #set the list for the port_descriptions
    port_description = []


    port_names = re.compile(r'<name>.*</name>')
    counter = 0
    #while counter < len(port_number):
    for ports in search_port:
        ports = str(ports)
        find_ports = port_names.findall(ports)    
        find_ports = " ".join(find_ports)
        if "name" in find_ports:

            find_ports = find_ports.replace("<name>", "").replace("</name>", "")
            print find_ports
            port_description.append(find_ports)
        else:
            port_description.append("")
        
    #set the list for the port numbers
    port_number = []
    port_names = re.compile(r'<number>.*</number>')
    counter = 0
    for ports in search_port:
        ports = str(ports)
        find_ports = port_names.findall(ports)    
        find_ports = " ".join(find_ports)
        if "number" in find_ports:
            #remove the tags and leave only the port numbers going into the list
            find_ports = find_ports.replace("<number>", "").replace("</number>", "")
            print find_ports
            port_number.append(find_ports)
        else:
            port_number.append("") 


    protocol_name = []

    protocol_names = re.compile(r'<protocol>.*</protocol>')
    counter = 0
    for protocol in search_port:
        ports = str(ports)
        find_ports = port_names.findall(ports)    
        find_ports = " ".join(find_ports)
        if "protocol" in find_ports:
        #remove the tags and leave only the protocol names going into the list

            find_ports = find_ports.replace("<protocol>", "").replace("</protocol>", "")
            protocol_name.append(find_ports)
        else:
            protocol_name.append("")

        #############Begin parsing nmap###################
    port_list = []
    nmap_file = open(scratch_file)
    for line in nmap_file:
        if line.startswith('Nmap'):
            flag = 0
        if last_line in line:
            flag = 1
        if not flag and not last_line in line:
            #append the line to the list and strip the dashes away
            port_list.append(line.strip('---').rstrip())
    
    #set the computer_id to 0. The computer_id represents the ID of the computer
    #each port can have the same ID. In this way ports 80, 22, 443 etc all reference computer by ID
    computer_id = 0
    existing_ports = []
    for ports_open in port_list:
        starts_with_digit = re.match(r"[0-9]", ports_open) is not None
        #For the ports section we dont want anything that starts with a letter
        #If the line starts with a digit, parse out only the port number
        if starts_with_digit == True:
            ports_open = ports_open.split('/')[0]
            print "Inserting: ", ports_open
            existing_ports.append(ports_open)
            cursor.execute("INSERT ignore INTO Ports_Table(Port_ID, Open_Port) values('%s','%s')" % (computer_id, ports_open))
            continue
        #If the line starts with Port, increase the computer_id. Nmap lists the PORT heading only once per computer
        #Therefore it is a reliable way to indicate the ID of a new computer
        elif starts_with_digit == False and "Nmap" in ports_open:
            computer_id +=1
        elif "All 1000" in ports_open:
            print "no ports open at ID ", computer_id
            ports_open = 0
            cursor.execute("INSERT ignore INTO Ports_Table(Port_ID, Open_Port) values('%s','%s')" % (computer_id, ports_open))
    #Loop through the open ports on your network and only add port descriptions of ports which exist on your network
    #This was done to reduce querry time against the list of known ports
    x = 0
    while x < len(port_number):
        if port_number[x] in existing_ports:
            print "adding ", port_number[x], port_description[x], protocol_name[x], " to the database"
            cursor.execute("INSERT ignore INTO Port_Description(Port_Number, Port_Description, Port_Protocol) values('%s', '%s', '%s')" % (port_number[x], port_description[x], protocol_name[x]))
        else:
            print "This port is not found among the open ports on your network.... OMITTING"
        x +=1
#######################################################################   
def parse_os():
    OS_list = []
    nmap_file = open(scratch_file)
    for line in nmap_file:
        if line.startswith('Nmap'):
            flag = 0
        if last_line in line:
            flag = 1
        if not flag and not last_line  in line:
            #append the line to the list and strip the dashes away
            OS_list.append(line.strip('---').rstrip())
    #set the computer_id to 0. The computer_id represents the ID of the computer
    #Each computer will only have a single OS at the time of scanning. Link the ID to the OS
    computer_id = 0
    for host_os in OS_list:
        starts_with_digit = re.match(r"[0-9]", host_os) is not None
        #If the line starts with a digit, skip it and look for the OS information
        if starts_with_digit == True:
            continue
        #If the line starts with Port, increase the computer_id. Nmap lists the PORT heading only once per computer
        #Therefore it is a reliable way to indicate the ID of a new computer
        elif "Nmap" in host_os:
            computer_id +=1
        elif "OS" in host_os and "OS:" not in host_os and "Warn" not in host_os and "Running"not in host_os and "Agg" not in host_os and "Microsoft" not in host_os :
            host_os = host_os.strip("OS details: ")
            if "No" in host_os or "Too many" in host_os:
                host_os = "Not available"
                print "Not available"
                cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os))
            else:
                host_os = host_os.split(",")
                print "Inserting: ", host_os[0]
                cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os[0]))
        elif "Microsoft" in host_os and "OS" not in host_os and "JUST" not in host_os:
            host_os = host_os.split("Running: ") 
            print "Inserting: ", host_os[1]
            cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os[1]))
##############################################################################
createNmap()

parse_ports()
parse_dns()
parse_os()
#close the database connection
database_connection.commit()
cursor.close()
database_connection.close()
#clean up after yourself
#os.remove(scratch_file)
#os.remove(nmap_output)

Here is a down and dirty UI:

Code:
#!/usr/bin/python
#This program is being designed to be a front end for mysql


from Tkinter import *
import MySQLdb
import struct
import os
import re

#This is where the bulk of the decision making is made
#This class is used to turn the checkbox input into meaning database parameters
#In ddition, it does some error checking by making sure all of the input boxes
#have text in them, as well as making sure that only 1 very ending is checked        

class getResults:
    
        
    def __init__(self, parent):
       
        def formatListbox(msg, listbox_height):
            fetch_results = cursor.fetchall()

            global top
            #top = Frame(root)
            top = Toplevel()
            #top.pack()
            
            #top.title("Information retrieved")
            msg_title = Message (top, text="The following computers are running '%s'" % msg, width=80)
            msg_title.pack(pady=5)
            scrollbar = Scrollbar(top)
            scrollbar.pack(side=RIGHT, fill=Y)
            listbox = Listbox(top, yscrollcommand=scrollbar.set, width=100, height=listbox_height)
            listbox.pack(pady=15, padx=50)
            
            #This sets the spacing for the listbox it explicitely tells the program to print each element, one at a time, to the list box
                        
            for single_result in fetch_results:
                character_count = 0
                #set the first spacing
            #we know that in the quad octet of ips, 15 characters are the maximum there will ever be
            #Therefore set the spacing 
                first_spacing = " "
                spacing = " "
                #print len(single_result[0]), len(single_result[1]), len(single_result[2])
                
                if (15 - len(single_result[0])) > 2:               
                    first_spacing = (first_spacing * 9)
                elif (15 - len(single_result[0])) > 1:
                    first_spacing = (first_spacing * 7)                                    
                elif (15 - len(single_result[0])) == 1:
                    first_spacing = (first_spacing * 5)
                
                if "Linux 2.6.13 - 2.6.28" in single_result[1] or "Linux 2.6.18 - 2.6.28" in single_result[1] or "Linux 2.6.24 - 2.6.31" in single_result[1] or "Linux 2.6.19 - 2.6.31" in single_result[1]:
                    spacing = (spacing * 45)
                elif "Microsoft Windows XP" in single_result[1]:
                    spacing = (spacing * 44)
                elif "Microsoft Windows Vista|2008|7" in single_result[1]:
                    spacing = (spacing * 29)
                    print "Found Vista|2008|7"
                elif "Microsoft Windows 2003" in single_result[1]:
                    spacing = (spacing * 40)
                elif "Not available" in single_result[1]:
                    spacing = (spacing * 58)
                elif "Linux 2.4.20" in single_result[1]:
                    spacing = (spacing * 58)
                elif "IBM InfoPrint 1140 printer" in single_result[1]:
                    spacing = (spacing * 37)
                elif "Linux 2.4.18 - 2.4.35 (likely embedded)" in single_result[1]:
                    spacing = (spacing * 17)
                elif "Dell 5210n or Lexmark C534dn" in single_result[1]:
                    spacing = (spacing * 29)
                elif "HP LaserJet 4250 printer (J7949E)" in single_result[1]:
                    spacing = (spacing * 25)
                elif "Microsoft Windows Vista" in single_result[1]:
                    spacing = (spacing * 41) 
                elif "APC AP7851 power distribution unit (AOS 2.7.0)" in single_result[1]:
                    spacing = (spacing * 4) 
                elif "WatchGuard FireBox 700 or X700 firew" in single_result[1]:
                    spacing = (spacing * 18) 
                elif "HP InkJet 2300" in single_result[1]:
                    spacing = (spacing * 54)
                elif "FreeBSD 4.3-RELEASE or IBM AIX 5.3 - 6.1" in single_result[1]:
                    spacing = (spacing * 13) 
                elif "Netgear GSM7224 switch" in single_result[1]:
                    spacing = (spacing * 39)                
                   
                single_result = single_result[0] + first_spacing + single_result[1] + spacing + single_result[2]             
                listbox.insert(END, single_result)
            scrollbar.config(command=listbox.yview)

        oper_sys = OS.get()
        ip_get = IP.get()
        database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
        cursor = database_connection.cursor()
        starts_with_digit = re.match(r"[0-9]", ip_get) is not None
        
        #display_all_ports = display_ports.get()
        #if display_all_ports 
        
        if  oper_sys == "" and ip_get != "":
                starts_with_digit = re.match(r"[0-9]", ip_get) is not None
                if starts_with_digit == True:
                    #cursor.execute("SELECT Computer_Info.Computer_IP_Address,OS_Table.OS_Name FROM Computer_Info, OS_Table WHERE Computer_Info.Computer_ID=OS_Table.OS_ID AND Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton(Computer_IP_Address)" % ip_get)
                    
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % ip_get)
                    
                    #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
                    number_of_rows = int(cursor.rowcount) /4  
                    if number_of_rows < 6:
                        number_of_rows = 8
                    formatListbox(ip_get, number_of_rows)
                else:
                    print "you did not enter a valid IP!!!"
        elif oper_sys != "" and ip_get == "":
            starts_with_digit = re.match(r"[0-9]", oper_sys) is not None
            if starts_with_digit == False:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % oper_sys)
                    #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
                    number_of_rows = int(cursor.rowcount) /4  
                    if number_of_rows < 6:
                        number_of_rows = 8
                    formatListbox(oper_sys, number_of_rows)
            else:
                    print "you did not enter a valid Operating system!!!"
        else:
            #print "please enter ONLY the OS or the IP address!!!"
            cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name \
            FROM Computer_Ports AS CP \
            JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
            JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
            JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
            JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
            WHERE Computer_IP_Address LIKE '%%%s%%' and OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (ip_get, oper_sys))
            #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
            number_of_rows = int(cursor.rowcount) /4  
            if number_of_rows < 6:
                number_of_rows = 8
            formatListbox(oper_sys, number_of_rows)
#This class designs the UI and the button placement
#This class has a mix of local and global variables. Local variables are designated by the self.xxx
#Any UI element that must return a result has a seperate .pack() lines. This is because having checkButton(xxx text=xxx).pack() returns an error
#when attempting to extract a value            
class createUI:
    def __init__(self, parent):
        #export variables from this class so they are available in other classes
        
        global OS, IP, counter
    
        self.panel1 = Frame(parent.title("main window"))
        self.panel1.pack()
        self.frame1 = Frame(self.panel1)
        #in the first frame, create the directions and the input boxes
        self.OS_label = Message(self.frame1, text="Search by operating system", justify=LEFT, width=180).pack(pady=2)
        OS = Entry(self.frame1)
        OS.pack()
        OS.focus_set()
        self.IP_label = Message(self.frame1, text="Search by IP", justify=LEFT, width=180).pack(pady=3)
        IP = Entry(self.frame1)
        IP.pack(pady=14, padx=60)    
        self.frame1.pack()

        self.frame5 = Frame(self.panel1)
        #set the variables used by the checkboxes to an IntVar so that they can be evaluated as off or on
        display_ports = IntVar()
        ports_checkbutton = Checkbutton(self.frame5, text='Display Ports', onvalue = 1, offvalue = 0, variable=display_ports, width=10)
        ports_checkbutton.pack(side=LEFT)
        self.frame5.pack()

        self.frame6 = Frame(self.panel1)
        #lambda was used so that the button does not execute the addToDB class before click. addToDB requires an argument and self.database_button didn't work
        self.database_button = Button(self.frame6, text="Get results!")
        self.database_button.pack()
        self.database_button.configure(command=lambda btn = self.database_button: getResults(btn))
        self.quit_button = Button(self.frame6, text="Get me outta here", command=self.panel1.quit).pack()             
        self.frame6.pack()
  
######main loop #########  

root = Tk()

ui = createUI(root)
ui.panel1.mainloop()


I merged the IANA parsing and have 7zipped the xml file and attached it here


Below find an updated UI with gtk

Code:
#!/usr/bin/python
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
import MySQLdb
from Tkinter import *

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()
class Table_GUI:
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
	
    def delete_event(self, widget, event, data=None):
		return False

    def destroy(self, widget, data=None):
		gtk.main_quit()
		
    def __init__(self):
     
		# create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_geometry_hints(min_width=400, min_height=200)

        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
        
        self.vbox = gtk.VBox(False, 0)
        self.window.add(self.vbox)
        
        self.vbox.show()
		#For some reason I can't get the scrolled window to work...
        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        self.vbox.pack_start(self.scrolledwindow)
		
        self.frm_table = gtk.Frame()
        self.frm_table.set_shadow_type(gtk.SHADOW_NONE)
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.show_Table(oper_sys, ip_get, hostname_get)
        self.frm_table.show()
        self.vbox.pack_start(self.frm_table, True, True, 0)

        self.window.show()
    
    def show_Table(self, search_os, search_ip, search_hostname):
### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
        self.liststore = gtk.ListStore(str, str, str, str, str)
        #If the user is running a search on the hostname run these querries
        if search_hostname != "":
            if ports_check == 1:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_hostname))
            #Otherwise just return the relevent data
            else:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_hostname))
        
        
        #If the user has specified the IP and the OS to search, run this querry  
        if search_os != "" and search_ip !="":
        #Set up the querries. If the user has activted the checkbox, we need to include the ports in the querry
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        #If the user has specified an OS but not an IP run this
        elif search_os != "" and search_ip == "":
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        #If the user has specified an IP but not an OS run this
        elif search_os =="" and search_ip != "":
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                  cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)


        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql querry
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == 1:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []
        
        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])
                
            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])
                
            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  
        
        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == 1:
                self.liststore.append(
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
			)
            else:
                self.liststore.append(
            [ single_result[0], single_result[1], single_result[2], "" , "" ]
			)
            counter +=1
        # Treeview
        self.treeview = gtk.TreeView()
      	self.treeview.set_property("fixed-height-mode", False)
        
        # Columns
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        if ports_check == 1:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)
            
        self.treeview.set_model(self.liststore)
        self.treeview.set_headers_clickable(True)

        self.frm_table.add(self.treeview)
        self.treeview.show()
    def on_column_clicked(self, tc, user_data):
		self.liststore.set_sort_column_id(user_data, self.sort_order)

		if self.sort_order == gtk.SORT_ASCENDING:
			self.sort_order = gtk.SORT_DESCENDING
		else:
			self.sort_order = gtk.SORT_ASCENDING

		tc.set_sort_order(self.sort_order)

    def newColumn(self, title, index):
		self.cells[index] = gtk.CellRendererText()
		self.cells[index].set_property('cell-background-gdk', gtk.gdk.color_parse("#FFF"))
		
		self.columns[index] = gtk.TreeViewColumn(title, self.cells[index], text=index)
		self.columns[index].set_resizable(True)
		self.columns[index].set_reorderable(True)
		self.columns[index].set_sort_indicator(True)
		if(index == 0) : 
		    self.columns[index].set_min_width(130)
		if (index == 1) : 
		    self.columns[index].set_min_width(300)
		if (index == 2) :
		    self.columns[index].set_min_width(200)
		self.columns[index].connect("clicked", self.on_column_clicked, index)
		self.treeview.insert_column(self.columns[index], -1)
		
	# The main function
    def main(self):
		gtk.main()
        
class createUI:
    #this function allows the button to call the next GUI
    def pushButton(self, parent):
        global ports_check, oper_sys, ip_get, hostname_get
        ports_check = display_ports.get()
        oper_sys = OS.get()
        ip_get = IP.get()
        hostname_get = HOSTNAME.get()
        
        if hostname_get != "" and (oper_sys != "" or ip_get != ""):
            pass
        else:
            gui = Table_GUI()
            gui.main()
    def __init__(self, parent):
        #export variables from this class so they are available in other classes
        
        global OS, IP, HOSTNAME, counter, display_ports
    
        self.panel1 = Frame(parent.title("main window"))
        self.panel1.pack()
        self.frame1 = Frame(self.panel1)
        #in the first frame, create the directions and the input boxes
        self.OS_label = Message(self.frame1, text="Search by Operating System", justify=LEFT, width=180).pack(pady=2)
        OS = Entry(self.frame1)
        OS.pack()
        OS.focus_set()
        self.Hostname_lable = Message(self.frame1, text="Search by Hostname", justify=LEFT, width=180).pack(pady=2)
        HOSTNAME = Entry(self.frame1)
        HOSTNAME.pack()
        self.IP_label = Message(self.frame1, text="Search by IP", justify=LEFT, width=180).pack(pady=3)
        IP = Entry(self.frame1)
        IP.pack(pady=14, padx=60) 
          
        self.frame1.pack()

        self.frame5 = Frame(self.panel1)
        #set the variables used by the checkboxes to an IntVar so that they can be evaluated as off or on
        display_ports = IntVar()
        ports_checkbutton = Checkbutton(self.frame5, text='Display Ports', onvalue = 1, offvalue = 0, variable=display_ports, width=10)
        ports_checkbutton.pack(side=LEFT)
        self.frame5.pack()

        self.frame6 = Frame(self.panel1)
        #lambda was used so that the button does not execute the addToDB class before click. addToDB requires an argument and self.database_button didn't work
        self.database_button = Button(self.frame6, text="Get results!")
        self.database_button.pack()
        
    
        self.database_button.configure(command=lambda btn = self.database_button: self.pushButton(btn))
        
        self.quit_button = Button(self.frame6, text="Get me outta here", command=self.panel1.quit).pack()             
        self.frame6.pack()





if __name__ == "__main__":
    root = Tk()

    ui = createUI(root)
    ui.panel1.mainloop()


Added a completely GTK interface. Functional but could use some design help. Scroll bars added and slight redesign substituting liststore for treestore Oct 1, 2011

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
import gtk
import os
import sys
import MySQLdb

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()

class Application(gtk.Window):
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
####################
    def __init__(self):
        gtk.Window.__init__( self )
        self.set_title("Netowrk Scanner")
        self.set_position(gtk.WIN_POS_CENTER)
        self.create_widgets()
        self.connect_signals()

        #self.window.show_all()
        self.show_all()
        gtk.main()
##################        
    def create_widgets(self):
        #Ask the user to search by operating system
        self.vbox = gtk.VBox(spacing=10)
        self.operating_system_label_hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Operating System :")
        self.operating_system_label_hbox_1.pack_start(self.label)

        #Set a check box so the user can choose to display ports
        self.ports_hbox_8 = gtk.HBox(spacing=10)
        self.ports_check = gtk.CheckButton("Display Ports")
        self.ports_hbox_8.pack_start(self.ports_check)
        self.halign_ports = gtk.Alignment(0,1,1,0)
        self.halign_ports.add(self.ports_hbox_8)

        self.os_entry_hbox_2 = gtk.HBox(spacing=10)
        self.OS = gtk.Entry()
        self.os_entry_hbox_2.pack_start(self.OS)

        self.hostname_label_hbox_3 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Hostname:")
        self.hostname_label_hbox_3.pack_start(self.label)

        self.hostname_entry_hbox_4 = gtk.HBox(spacing=10)
        self.HOSTNAME = gtk.Entry()
        self.hostname_entry_hbox_4.pack_start(self.HOSTNAME)

        self.ip_label_hbox_5 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by IP:")
        self.ip_label_hbox_5.pack_start(self.label)

        self.ip_entry_hbox_6 = gtk.HBox(spacing=10)
        self.IP = gtk.Entry()
        self.ip_entry_hbox_6.pack_start(self.IP)

        self.buttons_hbox_7 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("Get Results!")
        self.buttons_hbox_7.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Get me Outta Here!")
        self.buttons_hbox_7.pack_start(self.button_exit)

        #The order in which you pack_start a widget is the order in which it is displayed on the screen
        self.vbox.pack_start(self.operating_system_label_hbox_1)
        self.vbox.pack_start(self.os_entry_hbox_2)
        self.vbox.pack_start(self.hostname_label_hbox_3)
        self.vbox.pack_start(self.hostname_entry_hbox_4)
        self.vbox.pack_start(self.ip_label_hbox_5)
        self.vbox.pack_start(self.ip_entry_hbox_6)
        self.vbox.pack_start(self.halign_ports, False, False, 3)
        self.vbox.pack_start(self.buttons_hbox_7)

        self.add(self.vbox)
##########################
    def connect_signals(self):
        #Have the buttons start 'listening' for user interaction
        self.button_ok.connect("clicked", self.button_click)
        self.button_exit.connect("clicked", self.exit_program)
########################
    def button_click(self, clicked):
        #This function gets the values of the input boxes as well as the check box
        #And then passes them to the show_table function so it can get the correct results from the database
        global ports_check, os, ip, hostname
        os = self.OS.get_text()
        ip = self.IP.get_text()
        hostname = self.HOSTNAME.get_text()
        ports_check = self.ports_check.get_active()
        if hostname != "" and (os != "" or ip != ""):
            error_message = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "If you know the hostname why are you searching with other options? Please search by hostname only")
            error_message.run()
            error_message.destroy()
            self.OS.set_text("")
            self.IP.set_text("")
            self.HOSTNAME.set_text("")
        else:
            self.show_Table(os, ip, hostname)
##############        
    def show_Table(self, search_os, search_ip, search_hostname):
    ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
         # Columns
        if ports_check == True:
            cols = ['IP Address', 'Operating System', 'Hostname', 'Ports', 'Protocol Name']
        else:
            cols = ['IP Address', 'Operating System', 'Hostname']
        """    
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        #I only want the ports columns to show if the user requests it because this calls different mysql querries
        if ports_check == True:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)
        """
        
        sequence = [str] * len(cols)
        self.treestore = gtk.TreeStore( * sequence)
        self.treestore.connect("rows-reordered", self.on_column_clicked)
        self.treeview = gtk.TreeView(self.treestore)
        self.treeview.cell = [None] * len(cols)
        self.treeview_column = [None] * len(cols)
        
        for column_number, col in enumerate(cols):
            self.treeview.cell[column_number] = gtk.CellRendererText()
            self.treeview_column[column_number] = gtk.TreeViewColumn(col, self.treeview.cell[column_number])
            self.treeview_column[column_number].add_attribute(self.treeview.cell[column_number], 'text', column_number)
            self.treeview_column[column_number].set_resizable(True)
            self.treeview_column[column_number].set_reorderable(True)
            self.treeview_column[column_number].set_sort_indicator(True)
            self.treeview_column[column_number].set_sort_column_id(column_number)
            self.treeview.append_column(self.treeview_column[column_number])
        
        self.scrollTree = gtk.ScrolledWindow()
        self.scrollTree.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrollTree.add(self.treeview)
        
        #If the user is running a search on the hostname run these querries
        if search_hostname != "":
            if ports_check == True:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_hostname))
            #Otherwise just return the relevent data
            else:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_hostname))
        
        
        #If the user has specified the IP and the OS to search, run this querry  
        if search_os != "" and search_ip !="":
        #Set up the querries. If the user has activted the checkbox, we need to include the ports in the querry
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        #If the user has specified an OS but not an IP run this
        elif search_os != "" and search_ip == "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        #If the user has specified an IP but not an OS run this
        elif search_os =="" and search_ip != "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                 cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)

        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql querry
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == True:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []

        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])

            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])

            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  

        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == True:
                self.treestore.append( None,
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
            )

            else:

                self.treestore.append(None,
            [ single_result[0], single_result[1], single_result[2] ]
            )
            counter +=1
        
        
        self.frm_table = gtk.Window()
        self.frm_table.set_default_size(600, 800)
        self.frm_table.set_title("Network scan results")
        #Change the background to white instead of grey
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.frm_table.add(self.scrollTree)
        self.frm_table.show_all()
###################### 
    def on_column_clicked(self, col1, col2, col3, col4 ):
        #This function allows the columns to be resorted upon click

        if self.sort_order == gtk.SORT_ASCENDING:
            self.sort_order = gtk.SORT_DESCENDING
        else:
            self.sort_order = gtk.SORT_ASCENDING

        #tc.set_sort_order(self.sort_order) 
###############        
    def exit_program(self, widget, callback_data=None):
        gtk.main_quit()
#---------------------------------------------
if __name__ == "__main__":
    app = Application() 
    database_connection.commit()
    cursor.close()
    database_connection.close()



TODO List:

--Not connect as ROOT to the database
--create a front end for retrieval
-rewrite front end in QT or other more friendly UI (requires tkinter and gtk)
--add user input with checkboxes for Nmap flags
--add user input for hosts and/or subnets to scan
--decide whether to destroy the database and recreate each time nmap is run.
--If updating is chosen over destroy, work the logic to make sure the proper tables/fields are updated
--remove duplications from OS table some how
-add a scroll bar some how
 

Attachments

  • port_numbers.xml.7z
    183.1 KB · Views: 86
Last edited:
One thing you remember when working with mysql is that a lot of things can be done via SQL. For example for a long time I was getting the results of a query and manually sorting them in python. Then I found out you can have the sql query sort it for you. I don't know if that will apply to you, but the remove duplications you can prevent them by using the IGNORE, or the ON DUPLICATE commands, first comment, or create a new table and then rename it to the old name.
 
One thing you remember when working with mysql is that a lot of things can be done via SQL. For example for a long time I was getting the results of a query and manually sorting them in python. Then I found out you can have the sql query sort it for you. I don't know if that will apply to you, but the remove duplications you can prevent them by using the IGNORE, or the ON DUPLICATE commands, first comment, or create a new table and then rename it to the old name.

I was actually aware of the on dup and insert ignore into.

problem is I am strugling with the logic of how to store

for example

computer 1 = windows
computer 2 = linux
computer 3 = windows

the OS table should thus have only 1 entry for each os (under this scenario) but how do I make sure it is tracking that comp 1 and 3 are each windows.

I haven't really nailed down how to do this (thinking foreign keys)

Any rate I am going to be spending time with my buddy who was a DBA this weekend if i dont think of it by then I'll have him help me out
 
I may be missing something, but is there a reason you're using so many tables?

Why not just have one table contain all of the information?
 
Why not just have one table contain all of the information?
This is fundamental of relational database modeling, specifically normalization. Basically instead of replicating the same piece of data, you put it in a separate table and relate to it using a foreign key. When you change the single piece in the other table, that foreign key will point to the updated piece.
 
But if your database is being built dynamically each time you run the script, there would be no way for data to change?

Perhaps I'm not correctly understanding what exactly will be stored in here, as I'm not too familiar with nmap, but doesn't it show open connections on your network? It seems to me that you'd only need two tables.. open_ports, and then a table for the systems on which you're running the scan. This is under the assumption that your network layout looks like this:

System 1: OS=Windows, Static IP (or even dynamic since your DB is created dynamically) = xxx.xxx.xx.x, dns name="server1"
System 2: OS=Linux, Static IP (or even dynamic since your DB is created dynamically) = xxx.xxx.xx.x, dns name="server2"
System 3: OS=Windows, Static IP (or even dynamic since your DB is created dynamically) = xxx.xxx.xx.x, dns name="server3"

If this is the case, you would only need a relationship between your systems table and your open ports table, where the open ports table contains the primary key (as a foreign key) of the systems table.

[edit] I just realized that there would indeed be some minor redundancy if you have the same ports open on multiple systems. In which case, you'd need an associative table between the two. Doing so should put you in 3NF, right?
Although, it's been a long time since I messed with database conceptualization.. most of the tables I deal with daily are already created.. :).. I could be completely wrong.
 
The point I was trying to achieve was not the easiest program but rather one with good overall form.

If you want to scale this out to a large number of computers for example redundancy can hurt things. Also what I was trying to do is store the data in the best way possible so that functionality can be added without having to restructure the data. Messy data in means messy data out.

I am still going to pick away at this, though I just got back from vacation so I havent looked at it in a few weeks
 
DId a reorganization of the Database structure, updated and cleaned up the code base and added a rough UI
 
Edited for a slightly better UI, it now supports input for both OS and IP address for better filtering
 
bumping this up for an updated UI.

I consider this to be a BETA release.
The database methods may not be perfect and the front end needs more refinement but its quite functional as it stands

I am having some problems attempting to add a scroll bar. Does anyone have any experience with gtk and scroll bars?
 
Post some screen shots of the GTK only interface
 

Attachments

  • ports_showing.png
    ports_showing.png
    22.9 KB · Views: 802
  • no_ports.png
    no_ports.png
    32.9 KB · Views: 782
And on Windows 7
 

Attachments

  • ports_showing.png
    ports_showing.png
    46 KB · Views: 816
  • no_ports.png
    no_ports.png
    18.8 KB · Views: 924
Back