示例#1
0
	def to_file(self, filename):
		today = datetime.date.today();
		curser = int(self._serial);
		newser = int('{}{}{}00'.format(today.year, str(today.month).zfill(2), str(today.day).zfill(2)));
		while newser <= curser:
			newser += 1;
		self._records['@']['SOA'][0].serial = newser;
		self._getSOA();
		origin = "{}.".format(self._zname)
		z = dns.zone.Zone(dns.name.from_text(origin));
		
		for rname in self._records:
			for rtype in self._records[rname]:
				dset = dns.rdataset.Rdataset(rdc.from_text('IN'), rdt.from_text(rtype));
				dset.ttl = 300;
				for r in self._records[rname][rtype]:
					dset.add(r.to_rdata(origin=origin));
				z.replace_rdataset(rname, dset);
		
		tmpfile = '/tmp/tutu-dns-tmp-{}'.format(self._zname);
		z.to_file(tmpfile);
		fr = open(tmpfile, 'r');
		with open(filename, 'wt') as fh:
				fh.write("$ORIGIN {}\n$TTL 300\n".format(origin));
				for line in fr.readlines():
					fh.write(line);
示例#2
0
	def to_rdata(self, origin=dns.name.root):
		if not isinstance(origin, dns.name.Name):
			if type(origin) == str:
				origin = dns.name.from_text(origin);
		params = {};
		for attrib in self._slots:
			if attrib in ('mname', 'rname', 'target', 'exchange'):
				params[attrib] = dns.name.from_text(getattr(self, attrib), origin);
			elif attrib in ('serial', 'refresh', 'retry', 'expire',
										'minimum', 'priority', 'preference', 'port'):
				params[attrib] = int(getattr(self, attrib));
			else:
				params[attrib] = getattr(self, attrib);
		params['rdclass'] = rdc.from_text(self._rclass);
		params['rdtype'] = rdt.from_text(self._rtype);
		rdata = dns.rdata.get_rdata_class(rdc.from_text(self._rclass), rdt.from_text(self._rtype))(**params);
		return rdata;
示例#3
0
	def __init__(self, rtype, rclass='IN', ttl=300):
		self._rtype = rtype;
		self._rclass = rclass;
		self._ttl = ttl;
		
		if not self._check_type(rtype):
			raise NotImplementedError('Not a valid type ({})'.format(rtype));
		
		if not self._check_class(rclass):
			raise NotImplementedError('Not a valid class ({})'.format(rclass));
		
		self._slots = dns.rdata.get_rdata_class(rdc.from_text(rclass), rdt.from_text(rtype)).__slots__;
示例#4
0
	def delete(self):
			session = self.request.session;
			try:
				rzone = session['rzone'];
			except NameError:
				return HTTPFound('/dns/zones');
			
			try:
				oname = session['rname'];
				rtype = session['rtype'];
				odata = session['rdata'];
				rclass = session['rclass'];
			except NameError:
				return HTTPFound('/dns/zone/{}'.format(rzone));
			
			namedconf = tutuconfig.get('namedconf', 'dnsbind');
			ncp = NamedConfParser();
			ncp.from_file(namedconf);
			zonefile = ncp.find_zone_file(rzone);
			
			z = zone.from_file(zonefile);
			
			dset = z.get_rdataset(oname, rtype);
			newdset = dns.rdataset.Rdataset(rdc.from_text(rclass), rdt.from_text(rtype));
			newdset.ttl = 300;
			if rtype == 'SOA':
				newdset.add(rdata);
			else:
				for rd in dset:
					if odata == rd.to_text():
						pass
					else:
						newdset.add(rd);
			z.replace_rdataset(oname, newdset);
			
			tutuzone.save_zone(z, zonefile);
			
			return HTTPFound('/dns/zone/{}'.format(rzone));
# vim: set ts=2:
示例#5
0
    def resolve(self, name, qtype):
        '''

        Resolves a Blockchain-based (Namecoin) DNS Name via 2 step process using DNSSEC

        Step 1:
        -------
        Get NS and DS records for the Namecoin name (for example: www.mattdavid.bit) from the Namecoin Client

        Step 2:
        -------
        For each listed nameserver:

            - Create a temporary config file for use with unbound
            - Set Unbound's Trust Anchor to be the given DS records for the Namecoin-based domain name
            - Do DNSSEC-enabled DNS resolution for the given name / qtype


        :param name: DNS Record Name Query (for example: www.mattdavid.bit)
        :param qtype: String representation of query type (for example: A, AAAA, TXT, NS, SOA, etc...)
        :return: Resolved value if successful, None if un-successful
        '''

        name = name.rstrip('.')
        if not name.endswith('.bit'):
            raise ValueError('This is not a valid .bit domain')

        domains = name.split('.')
        domains.reverse()
        if len(domains) < 2:
            raise ValueError('At least SLD Required')

        # Get Namecoin-based Domain Info from Namecoin Blockchain
        nc_domain = self.nc_name_resolver.name_show(domains[1])
        if not nc_domain or not nc_domain.get('value'):
            log.error(
                'No Name Value Data Found for Namecoin-based Domain Name: d/%s'
                % domains[1])
            raise NamecoinValueException('No Name Value Data Found for: d/%s' %
                                         domains[1])

        nc_value = json.loads(nc_domain.get('value', '{}').replace('\'', '"'))
        if not nc_value.get('ds'):
            log.error(
                'No DS Records Present for Namecoin-based Domain Name: %s' %
                name)
            raise NoDSRecordException()

        if not nc_value.get('ns'):
            log.error(
                'No NS Records Present for Namecoin-based Domain Name: %s' %
                name)
            raise NoNameserverException()

        sld = '%s.%s.' % (domains[1], domains[0])
        ds_record = ' '.join([str(x) for x in nc_value['ds'][0][0:3]])

        # Handle both Hex and Base64 encoding (Base64 is the preferred encoding) per:
        # https://wiki.namecoin.info/index.php?title=Domain_Name_Specification
        if re.match('^[0-9a-fA-F]*$', nc_value['ds'][0][3]):
            ds_record += ' %s' % nc_value['ds'][0][3]
        else:
            ds_record += ' %s' % base64.b64decode(
                nc_value['ds'][0][3]).encode('hex').upper()

        ds_ta = '%s IN DS %s' % (sld, ds_record)

        ns_ctx = ub_ctx()
        ns_ctx.resolvconf(self.resolv_conf)

        if not os.path.isfile(self.dnssec_root_key):
            log.error("Trust anchor missing or inaccessible")
            raise Exception("Trust anchor is missing or inaccessible: %s" %
                            self.dnssec_root_key)
        else:
            ns_ctx.add_ta_file(self.dnssec_root_key)

        last_error = None
        for ns in nc_value.get('ns', []):

            lookup_value = None

            status, result = ns_ctx.resolve(ns, rdatatype.from_text('A'),
                                            rdataclass.from_text('IN'))

            # NOTE: We do not require secure DNS resolution here because the Blockchain-stored DS records work as the trust anchor
            # and the signed RRSIG DNS results from the final DNS+DNSSEC lookup will be able to complete the chain of trust
            if status == 0 and result and result.data and not result.bogus:
                tmp_config_file = self._build_temp_unbound_config(
                    sld,
                    result.data.as_address_list()[0])
            else:
                last_error = InvalidNameserverException()
                log.warn('No or Invalid Resolution Result for Nameserver: %s' %
                         ns)
                continue

            ctx = ub_ctx()
            ctx.config(tmp_config_file)
            ctx.add_ta(str(ds_ta))

            _qtype = None
            try:
                _qtype = rdatatype.from_text(qtype)
            except Exception as e:
                log.error(
                    'Unable to get RDATAType for Given Query Type [%s]: %s' %
                    (qtype, str(e)))
                raise ValueError('Unable to get RDATAType for Query Type %s' %
                                 qtype)

            status, result = ctx.resolve(name, _qtype,
                                         rdataclass.from_text('IN'))
            if status != 0:
                log.info("DNS Resolution Failed: %s [%s]" % (name, _qtype))
            elif status == 0:

                if not result.secure:
                    log.info(
                        "DNS Resolution Returned Insecure Result: %s [%s]" %
                        (name, qtype))
                    last_error = InsecureResultException()

                elif result.bogus:
                    log.info("DNS Resolution Returned Bogus Result: %s [%s]" %
                             (name, qtype))
                    last_error = BogusResultException()

                elif not result.havedata:
                    log.info("DNS Resolution Returned Empty Result: %s [%s]" %
                             (name, qtype))
                    last_error = EmptyResultException()

                else:
                    # Get appropriate data by query type
                    if qtype in ['A', 'AAAA']:
                        lookup_value = result.data.as_address_list()
                    elif qtype in ['CNAME', 'TXT']:
                        lookup_value = result.data.as_domain_list()
                    elif qtype in ['MX']:
                        lookup_value = result.data.as_mx_list()
                    else:
                        last_error = NotImplementedError(
                            'Unsupported DNS Query Type: %s' % qtype)

            self._delete_temp_unbound_config(tmp_config_file)

            if lookup_value:
                return lookup_value[0]

            if last_error and isinstance(last_error, NotImplementedError):
                raise last_error

        log.error('DNS Resolution Failed: %s [%s]' % (name, qtype))
        if last_error:
            raise last_error

        return None
示例#6
0
	def create(self):
		if self.posted():
			session = self.request.session;
			try:
				rzone = session['rzone'];
			except NameError:
				return HTTPFound('/dns/zones');
			
			try:
				oname = session['rname'];
				rtype = session['rtype'];
				odata = session['rdata'];
				rclass = session['rclass'];
			except NameError:
				return HTTPFound('/dns/zone/{}'.format(rzone));
			
			errors = {};
			errors['name'] = 0;
			rname = self.request.POST['name'];
			if len(rname) == 0:
				errors['name'] = 1;

			params = {};
			record = [];

			for data in self.request.POST:
				tmprec = {};
				tmprec['name'] = data;
				tmprec['value'] = self.request.POST[data];
				if data != 'name':
					record.append(tmprec);

				errors[data] = 0;

				if len(self.request.POST[data]) == 0:
					errors[data] = 1;
					continue;
				if data in ('serial', 'refresh', 'retry', 'expire',
											'minimum', 'priority', 'preference', 'port'):
					params[data] = int(self.request.POST[data]);
				elif data != 'name':
					params[data] = self.request.POST[data];
			

			errorcount = 0;
			for error in errors:
				errorcount += errors[error];
			if errorcount > 0:
				if rname == '@':
					pname = rzone;
				else:
					pname = "{}.{}".format(rname, rzone);

				return {'rname': rname, 'pname':pname, 'rzone': rzone, 'rtype': rtype, 
					'record': record, 'helpers':tuturecord.helpers, 'errors': errors};

			r = tuturecord.Record(rtype, rclass);
			for param in params:
				setattr(r, param, params[param]);
			
			z = tutuzone.Zone(rzone);
			z.load();
			
			z.replace_record(oname, odata, rname, r);
			
			z.save();
			
			return HTTPFound(location='/dns/zone/{}'.format(rzone));
		rzone = self.request.params.get('zone', None);
		
		if rzone is None:
			return HTTPFound(location='/dns/zones');
		
		rtype = self.request.params.get('type', None);
		if rtype is None:
			return HTTPFound(location='/dns/zone/{}'.format(rzone));
		
		z = tutuzone.Zone(rzone);
		
		if z.is_reverse():
			types = tuturecord.Record.reverse_supported_types;
		else:
			types = tuturecord.Record.forward_supported_types;
		
		if not rtype in types:
			return HTTPFound(location='/dns/zone/{}'.format(rzone));
		
		session = self.request.session;
		session['rzone'] = rzone;
		session['rname'] = None;
		session['rtype'] = rtype;
		session['rdata'] = None;
		session['rclass'] = 'IN';
		session.changed();
		
		slots = dns.rdata.get_rdata_class(rdc.from_text('IN'), rdt.from_text(rtype)).__slots__;
		
		record = [];
		errors = {};
		
		for slot in slots:
			errors[slot] = 0;
			record.append({'name': slot, 'value': ''});
		
		return {'rname': '', 'pname':'', 'rzone': rzone, 'rtype': rtype,
						'record': record, 'helpers':tuturecord.helpers, 'errors': errors, 'newrecord': True};
示例#7
0
    def resolve(self, name, qtype):
        '''

        Resolves a Blockchain-based (Namecoin) DNS Name via 2 step process using DNSSEC

        Step 1:
        -------
        Get NS and DS records for the Namecoin name (for example: www.mattdavid.bit) from the Namecoin Client

        Step 2:
        -------
        For each listed nameserver:

            - Create a temporary config file for use with unbound
            - Set Unbound's Trust Anchor to be the given DS records for the Namecoin-based domain name
            - Do DNSSEC-enabled DNS resolution for the given name / qtype


        :param name: DNS Record Name Query (for example: www.mattdavid.bit)
        :param qtype: String representation of query type (for example: A, AAAA, TXT, NS, SOA, etc...)
        :return: Resolved value if successful, None if un-successful
        '''

        name = name.rstrip('.')
        if not name.endswith('.bit'):
            raise ValueError('This is not a valid .bit domain')

        domains = name.split('.')
        domains.reverse()
        if len(domains) < 2:
            raise ValueError('At least SLD Required')

        # Get Namecoin-based Domain Info from Namecoin Blockchain
        nc_domain = self.nc_name_resolver.name_show(domains[1])
        if not nc_domain or not nc_domain.get('value'):
            log.error('No Name Value Data Found for Namecoin-based Domain Name: d/%s' % domains[1])
            raise NamecoinValueException('No Name Value Data Found for: d/%s' % domains[1])

        nc_value = json.loads(nc_domain.get('value', '{}').replace('\'','"'))
        if not nc_value.get('ds'):
            log.error('No DS Records Present for Namecoin-based Domain Name: %s' % name)
            raise NoDSRecordException()

        if not nc_value.get('ns'):
            log.error('No NS Records Present for Namecoin-based Domain Name: %s' % name)
            raise NoNameserverException()

        sld = '%s.%s.' % (domains[1], domains[0])
        ds_record = ' '.join([str(x) for x in nc_value['ds'][0][0:3]])

        # Handle both Hex and Base64 encoding (Base64 is the preferred encoding) per:
        # https://wiki.namecoin.info/index.php?title=Domain_Name_Specification
        if re.match('^[0-9a-fA-F]*$', nc_value['ds'][0][3]):
            ds_record += ' %s' % nc_value['ds'][0][3]
        else:
            ds_record += ' %s' % base64.b64decode(nc_value['ds'][0][3]).encode('hex').upper()

        if qtype in ['DS']:
            return ds_record
        ds_ta = '%s IN DS %s' % (sld, ds_record)

        ns_ctx = ub_ctx()
        ns_ctx.resolvconf(self.resolv_conf)

        if not os.path.isfile(self.dnssec_root_key):
            log.error("Trust anchor missing or inaccessible")
            raise Exception("Trust anchor is missing or inaccessible: %s" % self.dnssec_root_key)
        else:
            ns_ctx.add_ta_file(self.dnssec_root_key)

        last_error = None
        for ns in nc_value.get('ns', []):

            lookup_value = None

            status, result = ns_ctx.resolve(ns, rdatatype.from_text('A'), rdataclass.from_text('IN'))

            # NOTE: We do not require secure DNS resolution here because the Blockchain-stored DS records work as the trust anchor
            # and the signed RRSIG DNS results from the final DNS+DNSSEC lookup will be able to complete the chain of trust
            if status == 0 and result and result.data and not result.bogus:
                tmp_config_file = self._build_temp_unbound_config(sld, result.data.as_address_list()[0])
            else:
                last_error = InvalidNameserverException()
                log.warn('No or Invalid Resolution Result for Nameserver: %s' % ns)
                continue

            ctx = ub_ctx()
            ctx.config(tmp_config_file)
            ctx.add_ta(str(ds_ta))

            _qtype = None
            try:
                _qtype = rdatatype.from_text(qtype)
            except Exception as e:
                log.error('Unable to get RDATAType for Given Query Type [%s]: %s' % (qtype, str(e)))
                raise ValueError('Unable to get RDATAType for Query Type %s' % qtype)

            status, result = ctx.resolve(name, _qtype, rdataclass.from_text('IN'))
            if status != 0:
                log.info("DNS Resolution Failed: %s [%s]" % (name, _qtype))
            elif status == 0:

                if not result.secure:
                    log.info("DNS Resolution Returned Insecure Result: %s [%s]" % (name, qtype))
                    last_error = InsecureResultException()

                elif result.bogus:
                    log.info("DNS Resolution Returned Bogus Result: %s [%s]" % (name, qtype))
                    last_error = BogusResultException()

                elif not result.havedata:
                    log.info("DNS Resolution Returned Empty Result: %s [%s]" % (name, qtype))
                    last_error = EmptyResultException()

                else:
                    # Get appropriate data by query type
                    # TODO: Add SOA Record Processing
                    if qtype in ['A','AAAA']:
                        lookup_value = result.data.as_address_list()
                    elif qtype in ['CNAME','TXT','PTR','SPF','CAA','NAPTR']:
                        lookup_value = result.data.as_domain_list()
                    elif qtype in ['MX']:
                        lookup_value = result.data.as_mx_list()
                    elif qtype in ['NS']:
                        lookup_value = nc_value.get('ns', [])
                    elif qtype in ['TLSA']:
                        lookup_value = [NamecoinResolver.tlsa_convert(result.rawdata[0])]
                    else:
                        last_error = NotImplementedError('Unsupported DNS Query Type: %s' % qtype)

            self._delete_temp_unbound_config(tmp_config_file)

            if lookup_value:
                return lookup_value[0]

            if last_error and isinstance(last_error, NotImplementedError):
                raise last_error

        log.error('DNS Resolution Failed: %s [%s]' % (name, qtype))
        if last_error:
            raise last_error

        return None
示例#8
0
	def from_text(self, val):
		rdata = dns.rdata.from_text(rdc.from_text(self._rclass), rdt.from_text(self._rtype), val);
		self.from_rdata(rdata);