]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
handle escapes outside of names when reading text format
authorBob Halley <halley@nominum.com>
Tue, 12 Jan 2010 23:14:46 +0000 (15:14 -0800)
committerBob Halley <halley@nominum.com>
Tue, 12 Jan 2010 23:14:46 +0000 (15:14 -0800)
16 files changed:
dns/rdtypes/ANY/CERT.py
dns/rdtypes/ANY/LOC.py
dns/rdtypes/ANY/NSEC.py
dns/rdtypes/ANY/NSEC3.py
dns/rdtypes/ANY/NXT.py
dns/rdtypes/IN/APL.py
dns/rdtypes/IN/DHCID.py
dns/rdtypes/IN/IPSECKEY.py
dns/rdtypes/IN/WKS.py
dns/rdtypes/dsbase.py
dns/rdtypes/keybase.py
dns/rdtypes/sigbase.py
dns/rdtypes/txtbase.py
dns/tokenizer.py
dns/zone.py
tests/tokenizer.py

index 225a9210f122466881fb5a74221373d10671d1d9..87d3cb667223f981852f382b17d04af164eeb6b6 100644 (file)
@@ -86,7 +86,7 @@ class CERT(dns.rdata.Rdata):
             raise dns.exception.SyntaxError, "bad algorithm type"
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
index 7fe1a80ecdc037c02bb9179f7fa8c75f87086faa..793c5afa579e43a476fa8d475132ddf2e3cb6701 100644 (file)
@@ -229,19 +229,19 @@ class LOC(dns.rdata.Rdata):
             t = t[0 : -1]
         altitude = float(t) * 100.0    # m -> cm
 
-        token = tok.get()
+        token = tok.get().unescape()
         if not token.is_eol_or_eof():
             value = token.value
             if value[-1] == 'm':
                 value = value[0 : -1]
             size = float(value) * 100.0        # m -> cm
-            token = tok.get()
+            token = tok.get().unescape()
             if not token.is_eol_or_eof():
                 value = token.value
                 if value[-1] == 'm':
                     value = value[0 : -1]
                 hprec = float(value) * 100.0   # m -> cm
-                token = tok.get()
+                token = tok.get().unescape()
                 if not token.is_eol_or_eof():
                     value = token.value
                     if value[-1] == 'm':
index ee9a009c264eea854bbf554548f96c3968d25077..d548b84e44ce742704ea985e27e64fa0afa9d2df 100644 (file)
@@ -54,7 +54,7 @@ class NSEC(dns.rdata.Rdata):
         next = next.choose_relativity(origin, relativize)
         rdtypes = []
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             nrdtype = dns.rdatatype.from_text(token.value)
index 1d1782ff33b395541df01140ccd59ab261f7e42f..8833bc698349653e9bb21e4e04184d85d8632e19 100644 (file)
@@ -93,7 +93,7 @@ class NSEC3(dns.rdata.Rdata):
         next = base64.b32decode(next)
         rdtypes = []
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             nrdtype = dns.rdatatype.from_text(token.value)
index 10443a3b1b37b07579cc514064fc38a767b62c9e..07a99b71b98ff504e265b718e1d9849832e04c5a 100644 (file)
@@ -53,7 +53,7 @@ class NXT(dns.rdata.Rdata):
                   '\x00', '\x00', '\x00', '\x00',
                   '\x00', '\x00', '\x00', '\x00' ]
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             if token.value.isdigit():
index 21c02d5369c204b23f3b7c142f71976bea9408ae..8ac766646e534b6534bd73243d17ece8098432d0 100644 (file)
@@ -91,7 +91,7 @@ class APL(dns.rdata.Rdata):
     def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
         items = []
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             item = token.value
index 934d47846dcc2c9509f1b70c1f92fe8a9f61fe50..71bbe74b2f65edcc07d80f374f5780dff591277b 100644 (file)
@@ -35,7 +35,7 @@ class DHCID(dns.rdata.Rdata):
     def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
index 15eb546a8be3a976f74a31b7e1bf0c2deb8d57f1..2e1bfb378d460bb0546a32e721e2ea8faccd67f8 100644 (file)
@@ -86,7 +86,7 @@ class IPSECKEY(dns.rdata.Rdata):
             gateway = tok.get_string()
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
@@ -96,7 +96,7 @@ class IPSECKEY(dns.rdata.Rdata):
         key = b64.decode('base64_codec')
         return cls(rdclass, rdtype, precedence, gateway_type, algorithm,
                    gateway, key)
-    
+
     from_text = classmethod(from_text)
 
     def to_wire(self, file, compress = None, origin = None):
@@ -114,7 +114,7 @@ class IPSECKEY(dns.rdata.Rdata):
         else:
             raise ValueError, 'invalid gateway type'
         file.write(self.key)
-        
+
     def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
         if rdlen < 3:
             raise dns.exception.FormError
@@ -156,5 +156,5 @@ class IPSECKEY(dns.rdata.Rdata):
         other.to_wire(f)
         wire2 = f.getvalue()
         f.close()
-        
+
         return cmp(wire1, wire2)
index 4fdded6578d9c1fa479644140425b637109318d2..d3270a78fa647b3ab9f1a6b10868fcc5aefcca32 100644 (file)
@@ -60,7 +60,7 @@ class WKS(dns.rdata.Rdata):
             protocol = socket.getprotobyname(protocol)
         bitmap = []
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             if token.value.isdigit():
index 09b86cc1a0e4ab0b92480f64f2e69b29854d2f09..fb604c4fd521492af12597385148ed4de6e0e84b 100644 (file)
@@ -53,7 +53,7 @@ class DSBase(dns.rdata.Rdata):
         digest_type = tok.get_uint8()
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
index 52114f6adc6657ce8914595eb26a241f246d6bb4..a9a96fe892a415429e266f13975d5e2938aa771e 100644 (file)
@@ -112,7 +112,7 @@ class KEYBase(dns.rdata.Rdata):
         algorithm = dns.dnssec.algorithm_from_text(tok.get_string())
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
index e035bff39b713181efc828cf7d8bce731241bc9b..3430039af5cb45b9308ec8ea6b0ac294c8cc7de7 100644 (file)
@@ -109,7 +109,7 @@ class SIGBase(dns.rdata.Rdata):
         signer = signer.choose_relativity(origin, relativize)
         chunks = []
         while 1:
-            t = tok.get()
+            t = tok.get().unescape()
             if t.is_eol_or_eof():
                 break
             if not t.is_identifier():
index b3dd086db55d85965e9b016dc8fb6a029c2a0008..b87d7d6acb9400abc0a7a4350a7883840bdf6e94 100644 (file)
@@ -45,7 +45,7 @@ class TXTBase(dns.rdata.Rdata):
     def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
         strings = []
         while 1:
-            token = tok.get()
+            token = tok.get().unescape()
             if token.is_eol_or_eof():
                 break
             if not (token.is_quoted_string() or token.is_identifier()):
index cc4566ed5875357a3c0a7d0475b009784d1419f5..8253e0433dc05a4fada4f253ea40342fcd594059 100644 (file)
@@ -53,6 +53,8 @@ class Token(object):
     @type ttype: int
     @ivar value: The token value
     @type value: string
+    @ivar has_escape: Does the token value contain escapes?
+    @type has_escape: bool
     """
 
     def __init__(self, ttype, value='', has_escape=False):
@@ -108,6 +110,35 @@ class Token(object):
     def __str__(self):
         return '%d "%s"' % (self.ttype, self.value)
 
+    def unescape(self):
+        if not self.has_escape:
+            return self
+        unescaped = ''
+        l = len(self.value)
+        i = 0
+        while i < l:
+            c = self.value[i]
+            i += 1
+            if c == '\\':
+                if i >= l:
+                    raise dns.exception.UnexpectedEnd
+                c = self.value[i]
+                i += 1
+                if c.isdigit():
+                    if i >= l:
+                        raise dns.exception.UnexpectedEnd
+                    c2 = self.value[i]
+                    i += 1
+                    if i >= l:
+                        raise dns.exception.UnexpectedEnd
+                    c3 = self.value[i]
+                    i += 1
+                    if not (c2.isdigit() and c3.isdigit()):
+                        raise dns.exception.SyntaxError
+                    c = chr(int(c) * 100 + int(c2) * 10 + int(c3))
+            unescaped += c
+        return Token(self.ttype, unescaped)
+
 class Tokenizer(object):
     """A DNS master file format tokenizer.
 
@@ -264,6 +295,7 @@ class Tokenizer(object):
             return Token(WHITESPACE, ' ')
         token = ''
         ttype = IDENTIFIER
+        has_escape = False
         while True:
             c = self._get_char()
             if c == '' or c in self.delimiters:
@@ -341,13 +373,14 @@ class Tokenizer(object):
                     raise dns.exception.SyntaxError, 'newline in quoted string'
             elif c == '\\':
                 #
-                # Treat \ followed by a delimiter as the
-                # delimiter, otherwise leave it alone.
+                # It's an escape.  Put it and the next character into
+                # the token; it will be checked later for goodness.
                 #
+                token += c
+                has_escape = True
                 c = self._get_char()
-                if c == '' or not c in self.delimiters:
-                    self._unget_char(c)
-                    c = '\\'
+                if c == '' or c == '\n':
+                    raise dns.exception.UnexpectedEnd
             token += c
         if token == '' and ttype != QUOTED_STRING:
             if self.multiline:
@@ -393,7 +426,7 @@ class Tokenizer(object):
         @rtype: int
         """
 
-        token = self.get()
+        token = self.get().unescape()
         if not token.is_identifier():
             raise dns.exception.SyntaxError, 'expecting an identifier'
         if not token.value.isdigit():
@@ -436,7 +469,7 @@ class Tokenizer(object):
         @rtype: int
         """
 
-        token = self.get()
+        token = self.get().unescape()
         if not token.is_identifier():
             raise dns.exception.SyntaxError, 'expecting an identifier'
         if not token.value.isdigit():
@@ -454,7 +487,7 @@ class Tokenizer(object):
         @rtype: string
         """
 
-        token = self.get()
+        token = self.get().unescape()
         if not (token.is_identifier() or token.is_quoted_string()):
             raise dns.exception.SyntaxError, 'expecting a string'
         return token.value
@@ -466,7 +499,7 @@ class Tokenizer(object):
         @rtype: string
         """
 
-        token = self.get()
+        token = self.get().unescape()
         if not token.is_identifier():
             raise dns.exception.SyntaxError, 'expecting an identifier'
         return token.value
@@ -497,7 +530,7 @@ class Tokenizer(object):
         return token.value
 
     def get_ttl(self):
-        token = self.get()
+        token = self.get().unescape()
         if not token.is_identifier():
             raise dns.exception.SyntaxError, 'expecting an identifier'
         return dns.ttl.from_text(token.value)
index 6e1231f1f489569c0132d70bde7ef49493a91da8..5f2009b414280fc54839e9be5fba2d21186b6a5b 100644 (file)
@@ -654,7 +654,7 @@ class _MasterReader(object):
 
         try:
             while 1:
-                token = self.tok.get(True, True)
+                token = self.tok.get(True, True).unescape()
                 if token.is_eof():
                     if not self.current_file is None:
                         self.current_file.close()
index c5d41ac7768e0edefe3649471ce542cfb8535e11..29146eb7d4e80ee4529d9f2b0065182edfe97ddc 100644 (file)
@@ -159,12 +159,32 @@ class TokenizerTestCase(unittest.TestCase):
     def testEscapedDelimiter1(self):
         tok = dns.tokenizer.Tokenizer(r'ch\ ld')
         t = tok.get()
-        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch ld')
+        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld')
 
     def testEscapedDelimiter2(self):
         tok = dns.tokenizer.Tokenizer(r'ch\0ld')
         t = tok.get()
         self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\0ld')
 
+    def testEscapedDelimiter3(self):
+        tok = dns.tokenizer.Tokenizer(r'ch\032ld')
+        t = tok.get()
+        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld')
+
+    def testEscapedDelimiter1u(self):
+        tok = dns.tokenizer.Tokenizer(r'ch\ ld')
+        t = tok.get().unescape()
+        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\ ld')
+
+    def testEscapedDelimiter2u(self):
+        tok = dns.tokenizer.Tokenizer(r'ch\0ld')
+        t = tok.get().unescape()
+        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\0ld')
+
+    def testEscapedDelimiter3u(self):
+        tok = dns.tokenizer.Tokenizer(r'ch\032ld')
+        t = tok.get().unescape()
+        self.failUnless(t.ttype == dns.tokenizer.IDENTIFIER and t.value == r'ch\032ld')
+
 if __name__ == '__main__':
     unittest.main()