def _generate_line(self): # range lhs [ttl] [class] type rhs [ comment ] """Process one line containing the GENERATE statement from a DNS master file.""" if self.current_origin is None: raise UnknownOrigin token = self.tok.get() # Range (required) try: start, stop, step = grange.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except: raise exception.SyntaxError # lhs (required) try: lhs = token.value token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except: raise exception.SyntaxError # TTL try: ttl = ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except ttl.BadTTL: ttl = self.ttl # Class try: rdclass = rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except exception.SyntaxError: raise exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = rdatatype.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except: raise exception.SyntaxError("unknown rdatatype '%s'" % token.value) # lhs (required) try: rhs = token.value except: raise exception.SyntaxError lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) for i in range(start, stop + 1, step): # +1 because bind is inclusive and python is exclusive if lsign == '+': lindex = i + int(loffset) elif lsign == '-': lindex = i - int(loffset) if rsign == '-': rindex = i - int(roffset) elif rsign == '+': rindex = i + int(roffset) lzfindex = str(lindex).zfill(int(lwidth)) rzfindex = str(rindex).zfill(int(rwidth)) name = lhs.replace('$%s' % (lmod), lzfindex) rdata = rhs.replace('$%s' % (rmod), rzfindex) self.last_name = name.from_text(name, self.current_origin) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = rdata.from_text(rdclass, rdtype, rdata, self.current_origin, False) except exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def read(self): """Read a DNS master file and build a zone object. @raises zone.NoSOA: No SOA RR was found at the zone origin @raises zone.NoNS: No NS RRset was found at the zone origin """ try: while 1: token = self.tok.get(True, True) if token.is_eof(): if not self.current_file is None: self.current_file.close() if len(self.saved_state) > 0: (self.tok, self.current_origin, self.last_name, self.current_file, self.ttl) = self.saved_state.pop(-1) continue break elif token.is_eol(): continue elif token.is_comment(): self.tok.get_eol() continue elif token.value[0] == '$': u = token.value.upper() if u == '$TTL': token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError("bad $TTL") self.ttl = ttl.from_text(token.value) self.tok.get_eol() elif u == '$ORIGIN': self.current_origin = self.tok.get_name() self.tok.get_eol() if self.zone.origin is None: self.zone.origin = self.current_origin elif u == '$INCLUDE' and self.allow_include: token = self.tok.get() filename = token.value token = self.tok.get() if token.is_identifier(): new_origin = name.from_text(token.value, \ self.current_origin) self.tok.get_eol() elif not token.is_eol_or_eof(): raise exception.SyntaxError( "bad origin in $INCLUDE") else: new_origin = self.current_origin self.saved_state.append( (self.tok, self.current_origin, self.last_name, self.current_file, self.ttl)) self.current_file = file(filename, 'r') self.tok = tokenizer.Tokenizer(self.current_file, filename) self.current_origin = new_origin elif u == '$GENERATE': self._generate_line() else: raise exception.SyntaxError( "Unknown master file directive '" + u + "'") continue self.tok.unget(token) self._rr_line() except exception.SyntaxError, detail: (filename, line_number) = self.tok.where() if detail is None: detail = "syntax error" raise exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail))
def _rr_line(self): """Process one line from a DNS master file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading=True) if not token.is_whitespace(): self.last_name = name.from_text(token.value, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError # TTL try: ttl = ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except ttl.BadTTL: ttl = self.ttl # Class try: rdclass = rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except exception.SyntaxError: raise exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = rdatatype.from_text(token.value) except: raise exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, False) except exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def read(self): """Read a DNS master file and build a zone object. @raises zone.NoSOA: No SOA RR was found at the zone origin @raises zone.NoNS: No NS RRset was found at the zone origin """ try: while 1: token = self.tok.get(True, True) if token.is_eof(): if not self.current_file is None: self.current_file.close() if len(self.saved_state) > 0: (self.tok, self.current_origin, self.last_name, self.current_file, self.ttl) = self.saved_state.pop(-1) continue break elif token.is_eol(): continue elif token.is_comment(): self.tok.get_eol() continue elif token.value[0] == '$': u = token.value.upper() if u == '$TTL': token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError("bad $TTL") self.ttl = ttl.from_text(token.value) self.tok.get_eol() elif u == '$ORIGIN': self.current_origin = self.tok.get_name() self.tok.get_eol() if self.zone.origin is None: self.zone.origin = self.current_origin elif u == '$INCLUDE' and self.allow_include: token = self.tok.get() filename = token.value token = self.tok.get() if token.is_identifier(): new_origin = name.from_text(token.value, \ self.current_origin) self.tok.get_eol() elif not token.is_eol_or_eof(): raise exception.SyntaxError("bad origin in $INCLUDE") else: new_origin = self.current_origin self.saved_state.append((self.tok, self.current_origin, self.last_name, self.current_file, self.ttl)) self.current_file = file(filename, 'r') self.tok = tokenizer.Tokenizer(self.current_file, filename) self.current_origin = new_origin elif u == '$GENERATE': self._generate_line() else: raise exception.SyntaxError("Unknown master file directive '" + u + "'") continue self.tok.unget(token) self._rr_line() except exception.SyntaxError, detail: (filename, line_number) = self.tok.where() if detail is None: detail = "syntax error" raise exception.SyntaxError("%s:%d: %s" % (filename, line_number, detail))
def _rr_line(self): """Process one line from a DNS master file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading = True) if not token.is_whitespace(): self.last_name = name.from_text(token.value, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError # TTL try: ttl = ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except ttl.BadTTL: ttl = self.ttl # Class try: rdclass = rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise exception.SyntaxError except exception.SyntaxError: raise exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = rdatatype.from_text(token.value) except: raise exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, False) except exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def get_ttl(self): token = self.get().unescape() if not token.is_identifier(): raise exception.SyntaxError('expecting an identifier') return ttl.from_text(token.value)