예제 #1
0
    def resolve(self, request, handler):
        assert isinstance(request, DNSRecord)

        reply = request.reply()
        qname = request.q.qname
        D = self.D

        if request.q.qtype == QTYPE.NS and qname.matchSuffix(D):
            reply.add_answer(
                RR(rname=qname,
                   rtype=QTYPE.NS,
                   ttl=NS_TTL,
                   rdata=NS(D.add('ns'))))
            reply.add_ar(
                RR(D.add('ns'), QTYPE.A, ttl=self.ttl, rdata=A(self.ip)))

        # valid queries: data.data...data.9kw_api_key.operation.rest of domain
        elif request.q.qtype == QTYPE.CNAME\
          and len(qname.label) >= (len(D.label) + 2)\
          and qname.label[-(len(D.label) + 1)] in self.OPERATIONS\
          and qname.label[-(len(D.label) + 2)] in self.allowed_keys:

            operation = qname.label[-(len(D.label) + 1)]
            api_key = qname.label[-(len(D.label) + 2)]
            data = qname.label[:-(len(D.label) + 2)]

            ret = self.OPERATIONS[operation](api_key, data)
            reply.add_answer(RR(qname, QTYPE.CNAME, ttl=0, rdata=CNAME(ret)))

        return reply
예제 #2
0
    def craftPayload(self, msg):

        query = DNSRecord.parse(msg)
        response = query.reply()

        qname = query.q.qname
        vic_name = self.vic_name
        fakeip = self.fakeip

        if query.q.qtype == QTYPE.NS:
            print("[+] required NS record.")
            assert_ns = RR(qname, QTYPE.NS, ttl=60, rdata=NS("ns.%s" % qname))
            response.add_answer(assert_ns)

        elif query.q.qtype == QTYPE.A:
            print("[+] required any A record.")
            cnamerr = RR(qname, QTYPE.CNAME, ttl=60, rdata=CNAME(vic_name))
            fakea = RR(vic_name, QTYPE.A, ttl=86400, rdata=A(fakeip))
            response.add_answer(cnamerr)
            response.add_answer(fakea)

        if response.__class__.__name__ == "DNSRecord":
            print("[!] Debug: print reply data")
            print("===============================")
            print(response)
            print("===============================")
            return response.pack()
        else:
            return None
예제 #3
0
파일: dns.py 프로젝트: xiaoshuier/Mistica
 def createNsResponse(self, data, request):
     dataRawEnc = urlsafe_b64encode(data)
     dataEnc = str(dataRawEnc, "utf-8")
     self._LOGGING_ and self.logger.debug_all(
         f"[{self.name}] createNSResponse() with sotp_data: {dataEnc}")
     rdomain = self.getDomainFromRequest(request.q.qname.idna()[:-1])
     reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1),
                       q=request.q)
     reply.add_answer(
         RR(rname=request.q.qname,
            rtype=QTYPE.NS,
            rclass=CLASS.IN,
            ttl=self.ttl,
            rdata=NS(f"{dataEnc}.{rdomain}")))
     return reply
예제 #4
0
def RecordFactory(qtype: str, data: str, logger: Any) -> Any:
    if qtype == "A":
        return A(data)
    elif qtype == "CNAME":
        return CNAME(data)
    elif qtype == "AAAA":
        return AAAA(data)
    elif qtype == "NS":
        return NS(data)
    elif qtype == "MX":
        pref, entry = data.split()
        print(pref, entry)
        return MX(preference=int(pref), label=entry)
    else:
        logger.error("not implemented query type")
예제 #5
0
def main():
    root_path = DEFAULT_ROOT_PATH
    config = load_config(root_path, "config.yaml", SERVICE_NAME)
    initialize_logging(SERVICE_NAME, config["logging"], root_path)
    global D
    global ns
    global TTL
    global soa_record
    global ns_records
    D = DomainName(config["domain_name"])
    ns = DomainName(config["nameserver"])
    TTL = config["ttl"]
    soa_record = SOA(
        mname=ns,  # primary name server
        rname=config["soa"]["rname"],  # email of the domain administrator
        times=(
            config["soa"]["serial_number"],
            config["soa"]["refresh"],
            config["soa"]["retry"],
            config["soa"]["expire"],
            config["soa"]["minimum"],
        ),
    )
    ns_records = [NS(ns)]

    def signal_received():
        asyncio.create_task(kill_processes())

    loop = asyncio.get_event_loop()

    try:
        loop.add_signal_handler(signal.SIGINT, signal_received)
        loop.add_signal_handler(signal.SIGTERM, signal_received)
    except NotImplementedError:
        log.info("signal handlers unsupported")

    try:
        loop.run_until_complete(serve_dns())
    finally:
        loop.close()
예제 #6
0
def parse_request(data):
    """Parsing incomming data"""
    request = DNSRecord.parse(data)
    fqdn = [x.decode() for x in request.q.qname.label]
    city = '.'.join(fqdn[-3:-2])

    if '.'.join(fqdn[-2:]) == parse_config():
        # declare
        id_ = request.header.id
        rq_ = request.q
        qn_ = request.q.qname
        qt_ = request.q.qtype

        # generate message
        msg_ = get_weather(city, record=qt_)

        # generate dns reponse
        reply = DNSRecord(DNSHeader(id=id_, qr=1, aa=1, ra=1), q=rq_)
        if qt_ == QTYPE.A:
            if ('.'.join(fqdn) == parse_config(2)[0]) or ('.'.join(fqdn) == parse_config()):
                ip_, ttl_ = parse_config(qt_)
                reply.add_answer(RR(qn_, qt_, rdata=A(ip_), ttl=ttl_))
            else:
                for ip_ in msg_:
                    reply.add_answer(RR(qn_, qt_, rdata=A('.'.join(ip_))))

        elif qt_ == QTYPE.TXT:
            if len(msg_) > 255:
                for msg in textwrap.wrap(msg_.decode(), 255):
                    reply.add_answer(RR(qn_, qt_, rdata=TXT(msg)))
            else:
                reply.add_answer(RR(qn_, qt_, rdata=TXT(msg_)))

        elif qt_ == QTYPE.NS:
            ns_, ttl_ = parse_config(qt_)
            reply.add_answer(RR(qn_, qt_, rdata=NS(ns_), ttl=ttl_))

        elif qt_ == QTYPE.SRV:
            reply.add_answer(RR(qn_, qt_, rdata=SRV(*msg_)))
        return reply.pack()
예제 #7
0
    def query(self, peer, request):
        id = request.header.id
        qname = request.q.qname
        queryType = request.q.qtype
        reply = DNSRecord( DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q )

        def cnameRecursion(dHost):
            global tmpRes # used for overwriting previous recursion value
            tmpData = dbTest(dHost)
            # First: get CNAME of desired host
            cnameAddress = [i[1] for i in tmpData if i[0] == 'CNAME']
            tmpRes = (dHost,tmpData)
            if cnameAddress:
                newAddr = checkMacro(queryType,cnameAddress[0],dHost,peer)
                reply.add_answer(RR(dHost, QTYPE.CNAME, rdata=CNAME(newAddr)))
                # Second: get desired QTYPE from desired host
                printOut(peer,QTYPE.CNAME,str(dHost),newAddr)
                cnameRecursion(newAddr)
            return tmpRes

        qname,rData = cnameRecursion(qname)

        if queryType == QTYPE.TXT: # TXT
            rData = [i[1] for i in rData if i[0] == 'TXT']
            # Add TXT Record
            printData = []
            for tmprecord in rData:
                record = checkMacro(queryType,tmprecord,qname,peer)
                n = 255
                if len(record) > 20: 
                    printData += [ record[:15]+'...(%d)' % len(record) ]
                else:
                    printData = [record]
                if len(record) > n:
                    record = [record[i:i+n] for i in range(0, len(record), n)]
                reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(record if isinstance(record,list) else [record,])))
            printOut(peer,queryType,str(qname),printData)

        elif queryType == QTYPE.MX:
            rData = [i[1] for i in rData if i[0] == qTypeDict(queryType)]
            resIP = ''
            printData = []
            if len(rData):
                resIP = rData
            elif '*' in db:
                resIP = [i[1] for i in dbTest('*') if i[0] == 'MX']
            for tmpip in resIP:
                ip = checkMacro(queryType,tmpip,qname,peer)
                reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(ip)))
            printOut(peer,queryType,str(qname),printData)
            
        else:
            rData = [i[1] for i in rData if i[0] == qTypeDict(queryType)]
            resIP = ''
            if len(rData):
                resIP = rData
            elif '*' in db: # answer to ALL (*)
                resIP = [i[1] for i in dbTest('*') if i[0] == qTypeDict(queryType)]
            for tmpip in resIP:
                tip = checkMacro(queryType,tmpip,qname,peer)
                if not isinstance(tip,list):
                    tip = [tip]
                for ip in tip:
                    # Add A Record
                    if queryType == QTYPE.NS:
                        reply.add_answer(RR(qname, QTYPE.NS, rdata=NS(ip)))
                    elif queryType == QTYPE.AAAA:
                        if isValidIP(ip):
                            reply.add_answer(RR(qname, QTYPE.AAAA, rdata=AAAA(ip)))
                        else:
                            # Handle invalid IPv6, encode it in hex and send in form of IPv6
                            # Converting 'simpletext' -> ::7369:6d70:6c65:7465:7874
                            # To be used in 'file' macro
                            print("Invalid IPv6 provided: {!r}... Answering as HEX -> IPv6".format(ip[:20]))
                            n = 16
                            # if len(ip) > n:
                            if isinstance(ip,str):
                                ip = ip.encode()
                            record = [longToIP(int((ip[i:i+n]).hex(),16)) for i in range(0, len(ip), n)]
                            for i in record:
                                reply.add_answer(RR(qname, QTYPE.AAAA, rdata=AAAA(i)))
                    else:
                        reply.add_answer(RR(qname, QTYPE.A, rdata=A(ip), ttl=30))
            if resIP: 
                printOut(peer,queryType,str(qname),', '.join(resIP))
            else:
                printOut(peer,queryType,str(qname),'NONE')

        # Send To Client
        self.fire(write(peer, reply.pack()))
예제 #8
0
    def resolve(self, request, handler):
        reply = request.reply()

        # IP of inbound DNS request
        yourip = ipaddress.ip_address(unicode(handler.client_address[0]))

        # Wildcards if the --host supplied is 'any', otherwise limits to predefined --host
        if str(self.host).lower() == "any":
            hostname = str(request.q.qname)
        else:
            hostname = self.host

        # Build standard record contents for reply
        # e.g. local.test.	60	IN	SOA	ns1.local.test. hostmaster.local.test. 1 3600 600 604800 60
        soar = SOA("ns1." + hostname,
                   "hostmaster." + hostname,
                   (1, 3600, 600, 604800, 60))
        # e.g. local.test.	60	IN	NS	ns1.local.test.
        #      local.test.	60	IN	NS	ns2.local.test.
        ns1r = NS("ns1." + hostname)
        ns2r = NS("ns2." + hostname)

        """
        Request construction
          Verify that the request is valid, which records were requested, and construct the response
          Uses add_answer for Answer and add_auth for Authority response sections
        """

        # Matching hostname or --host 'any' was used
        if request.q.qname == hostname:

            # A record
            if QTYPE[request.q.qtype] == "A":
                # If A was requested but inbound is v6, return SOA with NOERROR ("no problem but nothing found")
                if type(yourip) == ipaddress.IPv6Address:
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.SOA,
                        rdata=soar,
                        ttl=60))
                    reply.header.rcode = RCODE.NOERROR
                # Otherwise return NS1, NS2, and A
                else:
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.NS,
                        rdata=ns1r,
                        ttl=60))
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.NS,
                        rdata=ns2r,
                        ttl=60))
                    reply.add_answer(RR(
                        hostname,
                        QTYPE.A,
                        rdata=A(str(yourip)),
                        ttl=60))

            # AAAA record
            elif QTYPE[request.q.qtype] == "AAAA":
                # If AAAA was requested but inbound is v4, return SOA with NOERROR ("no problem but nothing found")
                if type(yourip) == ipaddress.IPv4Address:
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.SOA,
                        rdata=soar,
                        ttl=60))
                    reply.header.rcode = RCODE.NOERROR
                # Otherwise return NS1, NS2, and AAAA
                else:
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.NS,
                        rdata=ns1r,
                        ttl=60))
                    reply.add_auth(RR(
                        hostname,
                        QTYPE.NS,
                        rdata=ns2r,
                        ttl=60))
                    reply.add_answer(RR(
                        hostname,
                        QTYPE.A,
                        rdata=AAAA(str(yourip)),
                        ttl=60))

            # TXT record
            #   Return NS1, NS2, and human-formatted TXT with IP address
            elif QTYPE[request.q.qtype] == "TXT":
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns1r,
                    ttl=60))   
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns2r,
                    ttl=60))
                reply.add_answer(RR(
                    hostname,
                    QTYPE.TXT,
                    rdata=TXT("Your IP is " + str(yourip)),
                    ttl=60))
            
            # NS record
            #   Return just NS1 and NS2
            elif QTYPE[request.q.qtype] == "NS":
                reply.add_answer(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns1r,
                    ttl=43200))
                reply.add_answer(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns2r,
                    ttl=43200))

            # SOA record
            #   Return just SOA
            elif QTYPE[request.q.qtype] == "SOA":
                reply.add_answer(RR(
                    hostname,
                    QTYPE.SOA,
                    rdata=soar,
                    ttl=60))

            # ANY record
            #   Returns A/AAAA, TXT, NS1, NS2, and SOA
            elif QTYPE[request.q.qtype] == "ANY":
                # AAAA for IPv6
                if type(yourip) == ipaddress.IPv6Address:
                    reply.add_answer(RR(
                        hostname,
                        QTYPE.A,
                        rdata=AAAA(str(yourip)),
                        ttl=60))
                # A for IPv4
                else:
                    reply.add_answer(RR(
                        hostname,
                        QTYPE.A,
                        rdata=A(str(yourip)),
                        ttl=60))
                # TXT
                reply.add_answer(RR(
                    hostname,
                    QTYPE.TXT,
                    rdata=TXT("Your IP is " + str(yourip)),
                    ttl=60))
                # NS1
                reply.add_answer(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns1r,
                    ttl=60))
                # NS2
                reply.add_answer(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns2r,
                    ttl=60))
                # SOA
                reply.add_answer(RR(
                    hostname,
                    QTYPE.SOA,
                    rdata=soar,
                    ttl=60))

            # All other types are invalid, e.g. MX or CNAME;
            #   Return only SOA and NOERROR ("no problem but nothing found")
            else:
                reply.add_auth(RR(
                    hostname,
                    QTYPE.SOA,
                    rdata=soar,
                    ttl=60))
                reply.header.rcode = RCODE.NOERROR

	# Respond with appropriate rset for NS1.hostname.tld (A/IPv4 only)
	#   Skipped for --host any, since we'd just use the same IP for NS1/NS2 anyway
        elif request.q.qname == "ns1." + hostname:
            # Only respond for A records, all others receive SOA and NOERROR ("no problem but nothing found")
            if QTYPE[request.q.qtype] == "A":
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns1r,
                    ttl=60))   
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns2r,
                    ttl=60))   
                reply.add_answer(RR(
                    "ns1." + hostname,
                    QTYPE.A,
                    rdata=A(myip),
                    ttl=60))
            else:
                reply.add_auth(RR(
                    hostname,
                    QTYPE.SOA,
                    rdata=soar,
                    ttl=60))   
                reply.header.rcode = RCODE.NOERROR

        # NS2.hostname.tld (A only)
        elif request.q.qname == "ns2." + hostname:
            # Only respond for A records, all others receive SOA and NOERROR ("no problem but nothing found")
            if QTYPE[request.q.qtype] == "A":
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns1r,
                    ttl=60))   
                reply.add_auth(RR(
                    hostname,
                    QTYPE.NS,
                    rdata=ns2r,
                    ttl=60))   
                reply.add_answer(RR(
                    "ns2." + hostname,
                    QTYPE.A,
                    rdata=A(myip),
                    ttl=60))
            else:
                reply.add_auth(RR(
                    hostname,
                    QTYPE.SOA,
                    rdata=soar,
                    ttl=60))
                reply.header.rcode = RCODE.NOERROR

        # Invalid host, correct domain? NXDOMAIN
        elif hostname in str(request.q.qname):
            reply.header.rcode = RCODE.NXDOMAIN
            reply.add_auth(RR(
                hostname,
                QTYPE.SOA,
                rdata=soar,   
                ttl=60))  
        
        # Invalid domain without --host any? REFUSED
        else:
            reply.header.rcode = RCODE.REFUSED

        # Return constructed rrset
        return reply
    def resolve(self, request, handler):
        """
        @type request: DNSRecord
        @type handler: DNSHandler
        """
        def nxdomain():
            reply = request.reply()
            reply.header.rcode = RCODE.NXDOMAIN
            return reply

        def refused():
            reply = request.reply()
            reply.header.rcode = RCODE.REFUSED
            return reply

        name = request.q.qname
        any_q = (request.q.qtype == QTYPE.ANY)

        # If they requested something other than our root domain that would be ~recursive, which we REFUSE.
        if not name.matchSuffix(settings.ROOT_DOMAIN):
            return refused()

        # If they requested our root domain exactly, they might want some DNS metadata stuff.
        if name == settings.ROOT_DOMAIN:
            reply = request.reply()
            if request.q.qtype == QTYPE.SOA or any_q:
                reply.add_answer(
                    RR(request.q.qname,
                       ttl=settings.TTL,
                       rtype=QTYPE.SOA,
                       rdata=SOA(mname=settings.NAMESERVERS[0],
                                 rname=settings.RNAME,
                                 times=(settings.SOA_TIMESTAMP, 300, 60,
                                        604800, 10))))
            if request.q.qtype == QTYPE.NS or any_q:
                for ns in settings.NAMESERVERS:
                    reply.add_answer(
                        RR(request.q.qname,
                           ttl=settings.TTL,
                           rtype=QTYPE.NS,
                           rdata=NS(ns)))
            return reply

        name = str(name.stripSuffix(settings.ROOT_DOMAIN))

        match = re.match(r'ip-(\d{1,3})-(\d{1,3})-(\d{1,3})-(\d{1,3})\.?',
                         name)

        if match is None:
            return nxdomain()

        ip = tuple(map(int, match.groups()))

        for octet in ip:
            if octet > 255:
                return nxdomain()

        # Now we return an empty response for not-A, or an actual response for A.
        # This is because we should not NXDOMAIN for domains that exist but have no records of
        # the specified type, so we have to go through the motions of checking validity first.
        reply = request.reply()
        if request.q.qtype == QTYPE.A or any_q:
            reply.add_answer(
                RR(request.q.qname,
                   ttl=settings.TTL,
                   rdata=A('%d.%d.%d.%d' % ip)))

        return reply