#!/usr/bin/env python2

"""
Module Firewall Test for Inguma
Copyright (c) 2007 Joxean Koret <joxeankoret@yahoo.es>

License is GPL
"""

import os
import sys
import time
import scapy
import socket
import random

from lib.libexploit import CIngumaModule

try:

    if os.name == "nt":
        from winscapy import IP, ICMP, TCP, sr, conf, getmacbyip, get_working_if
        import winscapy as scapy
    else:
        from scapy import IP, ICMP, TCP, sr, conf, getmacbyip, get_working_if
        import scapy

    hasScapy = True
except:
    hasScapy = False

name = "firetest"
brief_description = "A firewall testing tool"
type = "gather"

class CFirewallTest(CIngumaModule):

    SYN_SCAN = "S"
    TCP_SCAN = None
    ACK_SCAN = "A"
    XMAS_SCAN = "SAFRC"
    SA_SCAN = "SA"
    SF_SCAN = "SF"

    filtered = {}
    sport = random.randint(1024, 65535)
    scanType = SYN_SCAN
    exploitType = 1

    def help(self):
        print "target = <target host or network>"
        print "port = <target port>"
        print "timeout = <timeout>"
        print "iface = <interface to use>"

    def report_ports(self, target, ports):
        ans,unans = sr(IP(dst=target)/TCP(sport=self.sport, dport=ports, flags=self.scanType),timeout=self.timeout, iface=self.iface)

        for s,r in ans:
            if not r.haslayer(ICMP):
                try:
                    self.mac[r.src] = getmacbyip(r.src)
                except:
                    self.mac[r.src] = "ff:ff:ff:ff:ff"
                
                self.addToDict(r.src + "_mac", self.mac[r.src])

                if r.payload.flags == 0x12:
                    self.opened[r.sport] = r.src
                    print "  Discovered open port %d" % r.sport
                    self.addToDict(r.src + "_ports", r.sport)

        for s,r in ans:
            if r.haslayer(ICMP):
                self.closed[r.dport] = r.dst
            elif r.payload.flags != 0x12:
                self.closed[r.dport] = r.dst

        self.results = self.opened
        return True

    def scan(self):
        mTargets = IP(dst=self.target)

        for target in mTargets:
            for port in self.ports:
                self.report_ports(target.dst, port)

                if self.randomizeWaitTime:
                    mTime = random.randint(0,float(self.waitTime))
                else:
                    mTime = float(self.waitTime)

                time.sleep(mTime)

    def run(self):
        self.opened = {}
        self.closed = {}

        print "[+] Scanning for available IP protocols at %s" % self.target
        self.runCommand("protoscan")

        print "[+] Tracing route to %s" % self.target
        self.runCommand("trace")

        print "[+] Arpinging host %s" % self.target
        self.runCommand("arping")

        print "[+] ICMP probes with a MTU of 16"
        oldMTU = scapy.MTU
        scapy.MTU = 16
        self.doIcmpScan()

        print "[+] Restoring to the old MTU %d" % oldMTU
        scapy.MTU = oldMTU

        print "[+] ICMP probes"
        self.doIcmpScan()

        print "[+] TCP/IP probes"
        self.doScan()

        for port in self.opened:
            print
            print "Setting source port %d" % port
            self.sport = port
            self.doScan()
            
            print "[+] Checking if port", port, "is NATed:", self.runCommand("ispromisc")

        return True

    def doIcmpScan(self):
        packets = {
        "ECHO_REPLY":0,
        "DEST_UNREACH":3,
        "SOURCE_QUENCH":4,
        "REDIRECT":5,
        "ECHO_REQUEST":8,
        "ROUTER_ADVERTISEMENT":9,
        "ROUTER_SOLICITATION":10,
        "TIME_EXCEEDED":11,
        "PARAMETER_PROBLEM":12,
        "TIMESTAMP_REQUEST":13,
        "TIMESTAMP_REPLY":14,
        "INFORMATION_REQUEST":15,
        "INFORMATION_RESPONSE":16,
        "ADDRESS_MASK_REQUEST":17,
        "ADDRESS_MASK_REPPLY":18
        }

        for packet in packets:
            print "[+] Sending packet ICMP_%s ... " % packet
            self.runCommand("ping", {"packetType":packets[packet]})

    def doScan(self):
        print "[+] SYN scan against %s" % self.target
        self.scan()

        print "[+] SYN+FIN scan against %s" % self.target
        self.scanType = self.SF_SCAN
        self.scan()

        print "[+] ACK scan against %s" % self.target
        self.scanType = self.ACK_SCAN
        self.scan()

        print "[+] NULL scan (no flags) against %s" % self.target
        self.scanType = ""
        self.scan()

        print "[+] XMAS scan against %s" % self.target
        self.scanType = self.XMAS_SCAN
        self.scan()

        print "[+] SYN+ACK scan against %s" % self.target
        self.scanType = self.SA_SCAN
        self.scan()

    def printSummary(self):
        print
        print "Firetest results"
        print "----------------"
        print

        for port in self.opened:
            try:
                port_name = socket.getservbyport(port)
                port_name = str(port) + "/" + port_name
            except:
                port_name = str(port)

            print "Port", port_name,"is opened at", self.opened[port]

        print
