+ host = name[:-len(domain)-1]
+ value = invirt.database.NIC.query.filter_by(hostname=host).first()
+ if value:
+ ip = value.ip
+ else:
+ value = invirt.database.Machine.query().filter_by(name=host).first()
+ if value:
+ ip = value.nics[0].ip
+ else:
+ return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
+ if ip is None:
+ return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
+ if type in (dns.A, dns.ALL_RECORDS):
+ record = dns.Record_A(ip, ttl)
+ results.append(dns.RRHeader(name, dns.A, dns.IN,
+ ttl, record, auth=True))
+ elif type == dns.SOA:
+ results.append(dns.RRHeader(domain, dns.SOA, dns.IN,
+ ttl, self.soa, auth=True))
+
+ if len(results) == 0:
+ authority = []
+ additional = []
+ return defer.succeed((results, authority, additional))
+
+class DelegatingQuotingBindAuthority(authority.BindAuthority):
+ """
+ A delegating BindAuthority that (almost) deals with quoting correctly
+
+ This will catch double quotes as marking the start or end of a
+ quoted phrase, unless the double quote is escaped by a backslash
+ """
+ # Match either a quoted or unquoted string literal followed by
+ # whitespace or the end of line. This yields two groups, one of
+ # which has a match, and the other of which is None, depending on
+ # whether the string literal was quoted or unquoted; this is what
+ # necessitates the subsequent filtering out of groups that are
+ # None.
+ string_pat = \
+ re.compile(r'"((?:[^"\\]|\\.)*)"|((?:[^\\\s]|\\.)+)(?:\s+|\s*$)')
+
+ # For interpreting escapes.
+ escape_pat = re.compile(r'\\(.)')
+
+ def collapseContinuations(self, lines):
+ L = []
+ state = 0
+ for line in lines:
+ if state == 0:
+ if line.find('(') == -1:
+ L.append(line)
+ else:
+ L.append(line[:line.find('(')])
+ state = 1
+ else:
+ if line.find(')') != -1:
+ L[-1] += ' ' + line[:line.find(')')]
+ state = 0
+ else:
+ L[-1] += ' ' + line
+ lines = L
+ L = []
+
+ for line in lines:
+ in_quote = False
+ split_line = []
+ for m in self.string_pat.finditer(line):
+ [x] = [x for x in m.groups() if x is not None]
+ split_line.append(self.escape_pat.sub(r'\1', x))
+ L.append(split_line)
+ return filter(None, L)
+
+ def _lookup(self, name, cls, type, timeout = None):
+ maybeDelegate = False
+ deferredResult = authority.BindAuthority._lookup(self, name, cls,
+ type, timeout)
+ # If we didn't find an exact match for the name we were seeking,
+ # check if it's within a subdomain we're supposed to delegate to
+ # some other DNS server.
+ while (isinstance(deferredResult.result, failure.Failure)
+ and '.' in name):
+ maybeDelegate = True
+ name = name[name.find('.') + 1 :]
+ deferredResult = authority.BindAuthority._lookup(self, name, cls,
+ dns.NS, timeout)
+ # If we found somewhere to delegate the query to, our _lookup()
+ # for the NS record resulted in it being in the 'results' section.
+ # We need to instead return that information in the 'authority'
+ # section to delegate, and return an empty 'results' section
+ # (because we didn't find the name we were asked about). We
+ # leave the 'additional' section as we received it because it
+ # may contain A records for the DNS server we're delegating to.
+ if maybeDelegate and not isinstance(deferredResult.result,
+ failure.Failure):
+ (nsResults, nsAuthority, nsAdditional) = deferredResult.result
+ deferredResult = defer.succeed(([], nsResults, nsAdditional))
+ return deferredResult