BIND 10 trac831, updated. 9d0068f9fe027c66bd6231d633a0e67838e5b5be [trac831] Add src/lib/dns python generators for Windows (will be called for instance in pre-build events)

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Apr 6 14:59:40 UTC 2011


The branch, trac831 has been updated
       via  9d0068f9fe027c66bd6231d633a0e67838e5b5be (commit)
      from  6c611b5c04a5484df7269a603be4f00c4f7fa7f2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 9d0068f9fe027c66bd6231d633a0e67838e5b5be
Author: Francis Dupont <fdupont at isc.org>
Date:   Wed Apr 6 16:58:33 2011 +0200

    [trac831] Add src/lib/dns python generators for Windows
    (will be called for instance in pre-build events)

-----------------------------------------------------------------------

Summary of changes:
 ...{gen-rdatacode.py.in => gen-rdatacode.py.win32} |   22 ++++++++++----------
 .../{gen-wiredata.py.in => gen-wiredata.py.win32}  |    2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)
 copy src/lib/dns/{gen-rdatacode.py.in => gen-rdatacode.py.win32} (95%)
 mode change 100755 => 100644
 copy src/lib/dns/tests/testdata/{gen-wiredata.py.in => gen-wiredata.py.win32} (99%)
 mode change 100755 => 100644

-----------------------------------------------------------------------
diff --git a/src/lib/dns/gen-rdatacode.py.win32 b/src/lib/dns/gen-rdatacode.py.win32
new file mode 100644
index 0000000..879ea7e
--- /dev/null
+++ b/src/lib/dns/gen-rdatacode.py.win32
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+
+# Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+"""\
+This is a supplemental script to (half) auto-generate DNS Rdata related
+classes and constants.
+"""
+
+import os
+from os.path import getmtime
+import re
+import sys
+
+re_typecode = re.compile('([\da-z]+)_(\d+)')
+classcode2txt = {}
+typecode2txt = {}
+typeandclass = []
+generic_code = 65536            # something larger than any code value
+rdata_declarations = ''
+class_definitions = ''
+classdir_mtime = 0
+rdatadef_mtime = 0
+rdatahdr_mtime = 0
+heading_txt = '''///////////////
+///////////////
+///////////////   THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
+///////////////   DO NOT EDIT!
+///////////////
+///////////////
+
+'''
+
+def import_classdef(class_txt, file):
+    content = ''
+    rdata_source = open(file, 'r')
+    for line in rdata_source.readlines():
+        if re.match('// BEGIN_ISC_NAMESPACE', line):
+            content += 'namespace isc {\n'
+            content += 'namespace dns {\n'
+            continue
+        if re.match('// BEGIN_RDATA_NAMESPACE', line):
+            content += 'namespace rdata {\n'
+            content += 'namespace ' + class_txt + ' {\n'
+            continue
+        if re.match('// END_ISC_NAMESPACE', line):
+            content += '} // end of namespace "dns"\n'
+            content += '} // end of namespace "isc"\n'
+            continue
+        if re.match('// END_RDATA_NAMESPACE', line):
+            content += '} // end of namespace "' + class_txt +'"\n'
+            content += '} // end of namespace "rdata"\n'
+            continue
+        content += line
+    rdata_source.close()
+    return content
+
+def import_classheader(class_txt, type_txt, type_code, file):
+    type_utxt = type_txt.upper()
+    class_utxt = class_txt.upper()
+
+    # for each CLASS_n/TYPE_m.h
+    rdata_header = open(file, 'r')
+    content = ''
+    guard_macro = '__' + class_txt.upper() + '_' + type_txt.upper()
+    guard_macro += '_' + type_code + '_H'
+    for line in rdata_header.readlines():
+        if re.match('// BEGIN_HEADER_GUARD', line):
+            content += '#ifndef ' + guard_macro + '\n'
+            content += '#define ' + guard_macro + ' 1\n'
+            continue
+        if re.match('// END_HEADER_GUARD', line):
+            content += '#endif // ' + guard_macro + '\n'
+            continue
+        if re.match('// BEGIN_ISC_NAMESPACE', line):
+            content += 'namespace isc {\n'
+            content += 'namespace dns {\n'
+            continue
+        if re.match('// BEGIN_RDATA_NAMESPACE', line):
+            content += 'namespace rdata {\n'
+            content += 'namespace ' + class_txt + ' {\n'
+            continue
+        if re.match('// END_ISC_NAMESPACE', line):
+            content += '} // end of namespace "dns"\n'
+            content += '} // end of namespace "isc"\n'
+            continue
+        if re.match('// END_RDATA_NAMESPACE', line):
+            content += '} // end of namespace "' + class_txt +'"\n'
+            content += '} // end of namespace "rdata"\n'
+            continue
+        if re.match('// Local Variables:', line):
+            break
+        content += line
+        if re.match('// BEGIN_COMMON_DECLARATIONS', line):
+            content += '''
+class InputBuffer;
+class OutputBuffer;
+class MessageRenderer;\n\n'''
+        if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
+            content += '''
+    explicit ''' + type_utxt + '''(const std::string& type_str);
+    ''' + type_utxt + '''(InputBuffer& buffer, size_t rdata_len);
+    ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
+    virtual std::string toText() const;
+    virtual void toWire(OutputBuffer& buffer) const;
+    virtual void toWire(MessageRenderer& renderer) const;
+    virtual int compare(const Rdata& other) const;\n\n'''
+    rdata_header.close()
+    return content
+
+def import_definitions(classcode2txt, typecode2txt, typeandclass):
+    global rdata_declarations
+    global class_definitions
+    global classdir_mtime
+    global rdatadef_mtime
+    global rdatahdr_mtime
+
+    if classdir_mtime < getmtime('./rdata'):
+        classdir_mtime = getmtime('./rdata')
+
+    for dir in list(os.listdir('./rdata')):
+        classdir = './rdata' + os.sep + dir
+        m = re_typecode.match(dir)
+        if os.path.isdir(classdir) and (m != None or dir == 'generic'):
+            if dir == 'generic':
+                class_txt = 'generic'
+                class_code = generic_code
+            else:
+                class_txt = m.group(1)
+                class_code = m.group(2)
+                if not class_code in classcode2txt:
+                    classcode2txt[class_code] = class_txt
+            for file in list(os.listdir(classdir)):
+                file = classdir + os.sep + file
+                m = re_typecode.match(os.path.split(file)[1])
+                if m != None:
+                    type_txt = m.group(1)
+                    type_code = m.group(2)
+                    if not type_code in typecode2txt:
+                        typecode2txt[type_code] = type_txt
+                    if re.search('\cc$', file):
+                        if rdatadef_mtime < getmtime(file):
+                            rdatadef_mtime = getmtime(file)
+                        class_definitions += import_classdef(class_txt, file)
+                    elif re.search('\h$', file):
+                        if rdatahdr_mtime < getmtime(file):
+                            rdatahdr_mtime = getmtime(file)
+                        rdata_declarations += import_classheader(class_txt,
+                                                                 type_txt,
+                                                                 type_code,
+                                                                 file)
+                        typeandclass.append((type_txt, int(type_code),
+                                             (class_txt, class_txt),
+                                             int(class_code)))
+                        if class_txt == 'generic':
+                            typeandclass.append((type_txt, int(type_code),
+                                                 (class_txt, 'in'), 1))
+
+def need_generate(file, mtime):
+    '''Check if we need to generate the specified file.
+
+    To avoid unnecessary compilation, we skip (re)generating the file when
+    the file already exists and newer than the base file.
+    '''
+    if os.path.exists(file) and getmtime(file) > mtime:
+        return False
+    return True
+
+def generate_rdatadef(file, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    rdata_deffile = open(file, 'w')
+    rdata_deffile.write(heading_txt)
+    rdata_deffile.write(class_definitions)
+    rdata_deffile.close()
+
+def generate_rdatahdr(file, declarations, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    declarations += '''
+// Local Variables:
+// mode: c++
+// End:
+'''
+    rdata_header = open(file, 'w')
+    rdata_header.write(heading_txt)
+    rdata_header.write(declarations)
+    rdata_header.close()
+
+def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
+    placeholder = './' + fileprefix + '-placeholder.h'
+    outputfile = './' + fileprefix + '.h'
+    upper_key = type_or_class.upper() # TYPE or CLASS
+    lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
+    cap_key = type_or_class           # Type or Class
+
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
+
+    declarationtxt = ''
+    deftxt = ''
+    for code in code2txt.keys():
+        codetxt = code2txt[code].upper()
+        declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
+        deftxt += '''inline const RR''' + cap_key + '''&
+RR''' + cap_key + '''::''' + codetxt + '''() {
+    static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
+    return (''' + lower_key + ''');
+}\n
+'''
+    header_temp = open(placeholder, 'r')
+    header_out = open(outputfile, 'w')
+    header_out.write(heading_txt)
+    for line in header_temp.readlines():
+        header_out.write(line)
+        if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
+            header_out.write(declarationtxt)
+        if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
+            header_out.write('\n' + deftxt)
+    header_out.close()
+    header_temp.close()
+
+def generate_rrparam(fileprefix, basemtime):
+    placeholder = './' + fileprefix + '-placeholder.cc'
+    outputfile = './' + fileprefix + '.cc'
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
+
+    # sort by class, then by type
+    typeandclassparams = ''
+    typeandclass.sort(key = lambda x: (x[3], x[1]))
+    for param in typeandclass:
+        # for rrparamregistry.cc
+        # each param is a tuple of (type_txt, type_code, class_tuple,
+        #                           class_code)
+        (type_txt, type_code, class_tuple, class_code) = param
+        type_utxt = type_txt.upper()
+        class_txt = class_tuple[0]
+        class_utxt = class_tuple[1].upper()
+        indent = ' ' * 8
+        typeandclassparams += indent
+        if class_tuple[1] != 'generic':
+            typeandclassparams += 'add("' + type_utxt + '", '
+            typeandclassparams += str(type_code) + ', "' + class_utxt
+            typeandclassparams += '", ' + str(class_code)
+            typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
+            typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
+        else:
+            typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
+            typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
+            typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
+
+    rrparam_temp = open(placeholder, 'r')
+    rrparam_out = open(outputfile, 'w')
+    rrparam_out.write(heading_txt)
+    for line in rrparam_temp.readlines():
+        rrparam_out.write(line)
+        if re.match('\s+// BEGIN_WELL_KNOWN_PARAMS', line):
+            rrparam_out.write(typeandclassparams)
+    rrparam_temp.close()
+    rrparam_out.close()
+
+if __name__ == "__main__":
+    try:
+        import_definitions(classcode2txt, typecode2txt, typeandclass)
+        generate_rdatadef('./rdataclass.cc', rdatadef_mtime)
+        generate_rdatahdr('./rdataclass.h', rdata_declarations,
+                          rdatahdr_mtime)
+        generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
+        generate_typeclasscode('rrclass', classdir_mtime,
+                               classcode2txt, 'Class')
+        generate_rrparam('rrparamregistry', rdatahdr_mtime)
+    except:
+        sys.stderr.write('Code generation failed due to exception: %s\n' %
+                         sys.exc_info()[1])
+        exit(1)
diff --git a/src/lib/dns/tests/testdata/gen-wiredata.py.win32 b/src/lib/dns/tests/testdata/gen-wiredata.py.win32
new file mode 100644
index 0000000..befa39b
--- /dev/null
+++ b/src/lib/dns/tests/testdata/gen-wiredata.py.win32
@@ -0,0 +1,512 @@
+#!/usr/bin/python
+
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import configparser, re, time, sys
+from datetime import datetime
+from optparse import OptionParser
+
+re_hex = re.compile(r'^0x[0-9a-fA-F]+')
+re_decimal = re.compile(r'^\d+$')
+re_string = re.compile(r"\'(.*)\'$")
+
+dnssec_timefmt = '%Y%m%d%H%M%S'
+
+dict_qr = { 'query' : 0, 'response' : 1 }
+dict_opcode = { 'query' : 0, 'iquery' : 1, 'status' : 2, 'notify' : 4,
+                'update' : 5 }
+rdict_opcode = dict([(dict_opcode[k], k.upper()) for k in dict_opcode.keys()])
+dict_rcode = { 'noerror' : 0, 'formerr' : 1, 'servfail' : 2, 'nxdomain' : 3,
+               'notimp' : 4, 'refused' : 5, 'yxdomain' : 6, 'yxrrset' : 7,
+               'nxrrset' : 8, 'notauth' : 9, 'notzone' : 10 }
+rdict_rcode = dict([(dict_rcode[k], k.upper()) for k in dict_rcode.keys()])
+dict_rrtype = { 'none' : 0, 'a' : 1, 'ns' : 2, 'md' : 3, 'mf' : 4, 'cname' : 5,
+                'soa' : 6, 'mb' : 7, 'mg' : 8, 'mr' : 9, 'null' : 10,
+                'wks' : 11, 'ptr' : 12, 'hinfo' : 13, 'minfo' : 14, 'mx' : 15,
+                'txt' : 16, 'rp' : 17, 'afsdb' : 18, 'x25' : 19, 'isdn' : 20,
+                'rt' : 21, 'nsap' : 22, 'nsap_tr' : 23, 'sig' : 24, 'key' : 25,
+                'px' : 26, 'gpos' : 27, 'aaaa' : 28, 'loc' : 29, 'nxt' : 30,
+                'srv' : 33, 'naptr' : 35, 'kx' : 36, 'cert' : 37, 'a6' : 38,
+                'dname' : 39, 'opt' : 41, 'apl' : 42, 'ds' : 43, 'sshfp' : 44,
+                'ipseckey' : 45, 'rrsig' : 46, 'nsec' : 47, 'dnskey' : 48,
+                'dhcid' : 49, 'nsec3' : 50, 'nsec3param' : 51, 'hip' : 55,
+                'spf' : 99, 'unspec' : 103, 'tkey' : 249, 'tsig' : 250,
+                'dlv' : 32769, 'ixfr' : 251, 'axfr' : 252, 'mailb' : 253,
+                'maila' : 254, 'any' : 255 }
+rdict_rrtype = dict([(dict_rrtype[k], k.upper()) for k in dict_rrtype.keys()])
+dict_rrclass = { 'in' : 1, 'ch' : 3, 'hs' : 4, 'any' : 255 }
+rdict_rrclass = dict([(dict_rrclass[k], k.upper()) for k in \
+                          dict_rrclass.keys()])
+dict_algorithm = { 'rsamd5' : 1, 'dh' : 2, 'dsa' : 3, 'ecc' : 4,
+                   'rsasha1' : 5 }
+dict_nsec3_algorithm = { 'reserved' : 0, 'sha1' : 1 }
+rdict_algorithm = dict([(dict_algorithm[k], k.upper()) for k in \
+                            dict_algorithm.keys()])
+rdict_nsec3_algorithm = dict([(dict_nsec3_algorithm[k], k.upper()) for k in \
+                                  dict_nsec3_algorithm.keys()])
+
+header_xtables = { 'qr' : dict_qr, 'opcode' : dict_opcode,
+                   'rcode' : dict_rcode }
+question_xtables = { 'rrtype' : dict_rrtype, 'rrclass' : dict_rrclass }
+rrsig_xtables = { 'algorithm' : dict_algorithm }
+
+def parse_value(value, xtable = {}):
+    if re.search(re_hex, value):
+        return int(value, 16)
+    if re.search(re_decimal, value):
+        return int(value)
+    m = re.match(re_string, value)
+    if m:
+        return m.group(1)
+    lovalue = value.lower()
+    if lovalue in xtable:
+        return xtable[lovalue]
+    return value
+
+def code_totext(code, dict):
+    if code in dict.keys():
+        return dict[code] + '(' + str(code) + ')'
+    return str(code)
+
+def encode_name(name, absolute=True):
+    # make sure the name is dot-terminated.  duplicate dots will be ignored
+    # below.
+    name += '.'
+    labels = name.split('.')
+    wire = ''
+    for l in labels:
+        if len(l) > 4 and l[0:4] == 'ptr=':
+            # special meta-syntax for compression pointer
+            wire += ' %04x' % (0xc000 | int(l[4:]))
+            break
+        if absolute or len(l) > 0:
+            wire += '%02x' % len(l)
+            wire += ''.join(['%02x' % ord(ch) for ch in l])
+        if len(l) == 0:
+            break
+    return wire
+
+def encode_string(name, len=None):
+    if type(name) is int and len is not None:
+        return '%0.*x' % (len * 2, name)
+    return ''.join(['%02x' % ord(ch) for ch in name])
+
+def count_namelabels(name):
+    if name == '.':             # special case
+        return 0
+    m = re.match('^(.*)\.$', name)
+    if m:
+        name = m.group(1)
+    return len(name.split('.'))
+
+def get_config(config, section, configobj, xtables = {}):
+    try:
+        for field in config.options(section):
+            value = config.get(section, field)
+            if field in xtables.keys():
+                xtable = xtables[field]
+            else:
+                xtable = {}
+            configobj.__dict__[field] = parse_value(value, xtable)
+    except configparser.NoSectionError:
+        return False
+    return True
+
+def print_header(f, input_file):
+    f.write('''###
+### This data file was auto-generated from ''' + input_file + '''
+###
+''')
+
+class Name:
+    name = 'example.com'
+    pointer = None                # no compression by default
+    def dump(self, f):
+        name = self.name
+        if self.pointer is not None:
+            if len(name) > 0 and name[-1] != '.':
+                name += '.'
+            name += 'ptr=%d' % self.pointer
+        name_wire = encode_name(name)
+        f.write('\n# DNS Name: %s' % self.name)
+        if self.pointer is not None:
+            f.write(' + compression pointer: %d' % self.pointer)
+        f.write('\n')
+        f.write('%s' % name_wire)
+        f.write('\n')
+
+class DNSHeader:
+    id = 0x1035
+    (qr, aa, tc, rd, ra, ad, cd) = 0, 0, 0, 0, 0, 0, 0
+    mbz = 0
+    rcode = 0                   # noerror
+    opcode = 0                  # query
+    (qdcount, ancount, nscount, arcount) = 1, 0, 0, 0
+    def dump(self, f):
+        f.write('\n# Header Section\n')
+        f.write('# ID=' + str(self.id))
+        f.write(' QR=' + ('Response' if self.qr else 'Query'))
+        f.write(' Opcode=' + code_totext(self.opcode, rdict_opcode))
+        f.write(' Rcode=' + code_totext(self.rcode, rdict_rcode))
+        f.write('%s' % (' AA' if self.aa else ''))
+        f.write('%s' % (' TC' if self.tc else ''))
+        f.write('%s' % (' RD' if self.rd else ''))
+        f.write('%s' % (' AD' if self.ad else ''))
+        f.write('%s' % (' CD' if self.cd else ''))
+        f.write('\n')
+        f.write('%04x ' % self.id)
+        flag_and_code = 0
+        flag_and_code |= (self.qr << 15 | self.opcode << 14 | self.aa << 10 |
+                          self.tc << 9 | self.rd << 8 | self.ra << 7 |
+                          self.mbz << 6 | self.ad << 5 | self.cd << 4 |
+                          self.rcode)
+        f.write('%04x\n' % flag_and_code)
+        f.write('# QDCNT=%d, ANCNT=%d, NSCNT=%d, ARCNT=%d\n' %
+                (self.qdcount, self.ancount, self.nscount, self.arcount))
+        f.write('%04x %04x %04x %04x\n' % (self.qdcount, self.ancount,
+                                           self.nscount, self.arcount))
+
+class DNSQuestion:
+    name = 'example.com.'
+    rrtype = parse_value('A', dict_rrtype)
+    rrclass = parse_value('IN', dict_rrclass)
+    def dump(self, f):
+        f.write('\n# Question Section\n')
+        f.write('# QNAME=%s QTYPE=%s QCLASS=%s\n' %
+                (self.name,
+                 code_totext(self.rrtype, rdict_rrtype),
+                 code_totext(self.rrclass, rdict_rrclass)))
+        f.write(encode_name(self.name))
+        f.write(' %04x %04x\n' % (self.rrtype, self.rrclass))
+
+class EDNS:
+    name = '.'
+    udpsize = 4096
+    extrcode = 0
+    version = 0
+    do = 0
+    mbz = 0
+    rdlen = 0
+    def dump(self, f):
+        f.write('\n# EDNS OPT RR\n')
+        f.write('# NAME=%s TYPE=%s UDPSize=%d ExtRcode=%s Version=%s DO=%d\n' %
+                (self.name, code_totext(dict_rrtype['opt'], rdict_rrtype),
+                 self.udpsize, self.extrcode, self.version,
+                 1 if self.do else 0))
+        
+        code_vers = (self.extrcode << 8) | (self.version & 0x00ff)
+        extflags = (self.do << 15) | (self.mbz & 0x8000)
+        f.write('%s %04x %04x %04x %04x\n' %
+                (encode_name(self.name), dict_rrtype['opt'], self.udpsize,
+                 code_vers, extflags))
+        f.write('# RDLEN=%d\n' % self.rdlen)
+        f.write('%04x\n' % self.rdlen)
+
+class SOA:
+    # this currently doesn't support name compression within the RDATA.
+    rdlen = -1                  # auto-calculate
+    mname = 'ns.example.com'
+    rname = 'root.example.com'
+    serial = 2010012601
+    refresh = 3600
+    retry = 300
+    expire = 3600000
+    minimum = 1200
+    def dump(self, f):
+        mname_wire = encode_name(self.mname)
+        rname_wire = encode_name(self.rname)
+        rdlen = self.rdlen
+        if rdlen < 0:
+            rdlen = int(20 + len(mname_wire) / 2 + len(str(rname_wire)) / 2)
+        f.write('\n# SOA RDATA (RDLEN=%d)\n' % rdlen)
+        f.write('%04x\n' % rdlen);
+        f.write('# NNAME=%s RNAME=%s\n' % (self.mname, self.rname))
+        f.write('%s %s\n' % (mname_wire, rname_wire))
+        f.write('# SERIAL(%d) REFRESH(%d) RETRY(%d) EXPIRE(%d) MINIMUM(%d)\n' %
+                (self.serial, self.refresh, self.retry, self.expire,
+                 self.minimum))
+        f.write('%08x %08x %08x %08x %08x\n' % (self.serial, self.refresh,
+                                                self.retry, self.expire,
+                                                self.minimum))
+
+class TXT:
+    rdlen = -1                  # auto-calculate
+    nstring = 1                 # number of character-strings
+    stringlen = -1              # default string length, auto-calculate
+    string = 'Test String'      # default string
+    def dump(self, f):
+        stringlen_list = []
+        string_list = []
+        wirestring_list = []
+        for i in range(0, self.nstring):
+            key_string = 'string' + str(i)
+            if key_string in self.__dict__:
+                string_list.append(self.__dict__[key_string])
+            else:
+                string_list.append(self.string)
+            wirestring_list.append(encode_string(string_list[-1]))
+            key_stringlen = 'stringlen' + str(i)
+            if key_stringlen in self.__dict__:
+                stringlen_list.append(self.__dict__[key_stringlen])
+            else:
+                stringlen_list.append(self.stringlen)
+            if stringlen_list[-1] < 0:
+                stringlen_list[-1] = int(len(wirestring_list[-1]) / 2)
+        rdlen = self.rdlen
+        if rdlen < 0:
+            rdlen = int(len(''.join(wirestring_list)) / 2) + self.nstring
+        f.write('\n# TXT RDATA (RDLEN=%d)\n' % rdlen)
+        f.write('%04x\n' % rdlen);
+        for i in range(0, self.nstring):
+            f.write('# String Len=%d, String=\"%s\"\n' %
+                    (stringlen_list[i], string_list[i]))
+            f.write('%02x%s%s\n' % (stringlen_list[i],
+                                    ' ' if len(wirestring_list[i]) > 0 else '',
+                                    wirestring_list[i]))
+
+class NSECBASE:
+    '''Implements rendering NSEC/NSEC3 type bitmaps commonly used for
+    these RRs.  The NSEC and NSEC3 classes will be inherited from this
+    class.'''
+    nbitmap = 1                 # number of bitmaps
+    block = 0
+    maplen = None              # default bitmap length, auto-calculate
+    bitmap = '040000000003'     # an arbtrarily chosen bitmap sample
+    def dump(self, f):
+        # first, construct the bitmpa data
+        block_list = []
+        maplen_list = []
+        bitmap_list = []
+        for i in range(0, self.nbitmap):
+            key_bitmap = 'bitmap' + str(i)
+            if key_bitmap in self.__dict__:
+                bitmap_list.append(self.__dict__[key_bitmap])
+            else:
+                bitmap_list.append(self.bitmap)
+            key_maplen = 'maplen' + str(i)
+            if key_maplen in self.__dict__:
+                maplen_list.append(self.__dict__[key_maplen])
+            else:
+                maplen_list.append(self.maplen)
+            if maplen_list[-1] is None: # calculate it if not specified
+                maplen_list[-1] = int(len(bitmap_list[-1]) / 2)
+            key_block = 'block' + str(i)
+            if key_block in self.__dict__:
+               block_list.append(self.__dict__[key_block])
+            else:
+                block_list.append(self.block)
+
+        # dump RR-type specific part (NSEC or NSEC3)
+        self.dump_fixedpart(f, 2 * self.nbitmap + \
+                                int(len(''.join(bitmap_list)) / 2))
+
+        # dump the bitmap
+        for i in range(0, self.nbitmap):
+            f.write('# Bitmap: Block=%d, Length=%d\n' %
+                    (block_list[i], maplen_list[i]))
+            f.write('%02x %02x %s\n' %
+                    (block_list[i], maplen_list[i], bitmap_list[i]))
+
+class NSEC(NSECBASE):
+    rdlen = None                # auto-calculate
+    nextname = 'next.example.com'
+    def dump_fixedpart(self, f, bitmap_totallen):
+        name_wire = encode_name(self.nextname)
+        if self.rdlen is None:
+            # if rdlen needs to be calculated, it must be based on the bitmap
+            # length, because the configured maplen can be fake.
+            self.rdlen = int(len(name_wire) / 2) + bitmap_totallen
+        f.write('\n# NSEC RDATA (RDLEN=%d)\n' % self.rdlen)
+        f.write('%04x\n' % self.rdlen);
+        f.write('# Next Name=%s (%d bytes)\n' % (self.nextname,
+                                                 int(len(name_wire) / 2)))
+        f.write('%s\n' % name_wire)
+
+class NSEC3(NSECBASE):
+    rdlen = None                # auto-calculate
+    hashalg = 1                 # SHA-1
+    optout = False              # opt-out flag
+    mbz = 0                     # other flag fields (none defined yet)
+    iterations = 1
+    saltlen = 5
+    salt = 's' * saltlen
+    hashlen = 20
+    hash = 'h' * hashlen
+    def dump_fixedpart(self, f, bitmap_totallen):
+        if self.rdlen is None:
+            # if rdlen needs to be calculated, it must be based on the bitmap
+            # length, because the configured maplen can be fake.
+            self.rdlen = 4 + 1 + len(self.salt) + 1 + len(self.hash) \
+                + bitmap_totallen
+        f.write('\n# NSEC3 RDATA (RDLEN=%d)\n' % self.rdlen)
+        f.write('%04x\n' % self.rdlen)
+        optout_val = 1 if self.optout else 0
+        f.write('# Hash Alg=%s, Opt-Out=%d, Other Flags=%0x, Iterations=%d\n' %
+                (code_totext(self.hashalg, rdict_nsec3_algorithm),
+                 optout_val, self.mbz, self.iterations))
+        f.write('%02x %02x %04x\n' %
+                (self.hashalg, (self.mbz << 1) | optout_val, self.iterations))
+        f.write("# Salt Len=%d, Salt='%s'\n" % (self.saltlen, self.salt))
+        f.write('%02x%s%s\n' % (self.saltlen,
+                                ' ' if len(self.salt) > 0 else '',
+                                encode_string(self.salt)))
+        f.write("# Hash Len=%d, Hash='%s'\n" % (self.hashlen, self.hash))
+        f.write('%02x%s%s\n' % (self.hashlen,
+                                ' ' if len(self.hash) > 0 else '',
+                                encode_string(self.hash)))
+
+class RRSIG:
+    rdlen = -1                  # auto-calculate
+    covered = 1                 # A
+    algorithm = 5               # RSA-SHA1
+    labels = -1                 # auto-calculate (#labels of signer)
+    originalttl = 3600
+    expiration = int(time.mktime(datetime.strptime('20100131120000',
+                                                   dnssec_timefmt).timetuple()))
+    inception = int(time.mktime(datetime.strptime('20100101120000',
+                                                  dnssec_timefmt).timetuple()))
+    tag = 0x1035
+    signer = 'example.com'
+    signature = 0x123456789abcdef123456789abcdef
+    def dump(self, f):
+        name_wire = encode_name(self.signer)
+        sig_wire = '%x' % self.signature 
+        rdlen = self.rdlen
+        if rdlen < 0:
+            rdlen = int(18 + len(name_wire) / 2 + len(str(sig_wire)) / 2)
+        labels = self.labels
+        if labels < 0:
+            labels = count_namelabels(self.signer)
+        f.write('\n# RRSIG RDATA (RDLEN=%d)\n' % rdlen)
+        f.write('%04x\n' % rdlen);
+        f.write('# Covered=%s Algorithm=%s Labels=%d OrigTTL=%d\n' %
+                (code_totext(self.covered, rdict_rrtype),
+                 code_totext(self.algorithm, rdict_algorithm), labels,
+                 self.originalttl))
+        f.write('%04x %02x %02x %08x\n' % (self.covered, self.algorithm,
+                                           labels, self.originalttl))
+        f.write('# Expiration=%s, Inception=%s\n' %
+                (str(self.expiration), str(self.inception)))
+        f.write('%08x %08x\n' % (self.expiration, self.inception))
+        f.write('# Tag=%d Signer=%s and Signature\n' % (self.tag, self.signer))
+        f.write('%04x %s %s\n' % (self.tag, name_wire, sig_wire))
+
+class TSIG:
+    rdlen = None                # auto-calculate
+    algorithm = 'hmac-sha256'
+    time_signed = 1286978795    # arbitrarily chosen default
+    fudge = 300
+    mac_size = None             # use a common value for the algorithm
+    mac = None                  # use 'x' * mac_size
+    original_id = 2845          # arbitrarily chosen default
+    error = 0
+    other_len = None         # 6 if error is BADTIME; otherwise 0
+    other_data = None        # use time_signed + fudge + 1 for BADTIME
+    dict_macsize = { 'hmac-md5' : 16, 'hmac-sha1' : 20, 'hmac-sha256' : 32 }
+    def dump(self, f):
+        if str(self.algorithm) == 'hmac-md5':
+            name_wire = encode_name('hmac-md5.sig-alg.reg.int')
+        else:
+            name_wire = encode_name(self.algorithm)
+        rdlen = self.rdlen
+        mac_size = self.mac_size
+        if mac_size is None:
+            if self.algorithm in self.dict_macsize.keys():
+                mac_size = self.dict_macsize[self.algorithm]
+            else:
+                raise RuntimeError('TSIG Mac Size cannot be determined')
+        mac = encode_string('x' * mac_size) if self.mac is None else \
+            encode_string(self.mac, mac_size)
+        other_len = self.other_len
+        if other_len is None:
+            # 18 = BADTIME
+            other_len = 6 if self.error == 18 else 0
+        other_data = self.other_data
+        if other_data is None:
+            other_data = '%012x' % (self.time_signed + self.fudge + 1) \
+                if self.error == 18 else ''
+        else:
+            other_data = encode_string(self.other_data, other_len)
+        if rdlen is None:
+            rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
+                            len(other_data) / 2)
+        f.write('\n# TSIG RDATA (RDLEN=%d)\n' % rdlen)
+        f.write('%04x\n' % rdlen);
+        f.write('# Algorithm=%s Time-Signed=%d Fudge=%d\n' %
+                (self.algorithm, self.time_signed, self.fudge))
+        f.write('%s %012x %04x\n' % (name_wire, self.time_signed, self.fudge))
+        f.write('# MAC Size=%d MAC=(see hex)\n' % mac_size)
+        f.write('%04x%s\n' % (mac_size, ' ' + mac if len(mac) > 0 else ''))
+        f.write('# Original-ID=%d Error=%d\n' % (self.original_id, self.error))
+        f.write('%04x %04x\n' %  (self.original_id, self.error))
+        f.write('# Other-Len=%d Other-Data=(see hex)\n' % other_len)
+        f.write('%04x%s\n' % (other_len,
+                              ' ' + other_data if len(other_data) > 0 else ''))
+
+def get_config_param(section):
+    config_param = {'name' : (Name, {}),
+                    'header' : (DNSHeader, header_xtables),
+                    'question' : (DNSQuestion, question_xtables),
+                    'edns' : (EDNS, {}), 'soa' : (SOA, {}), 'txt' : (TXT, {}),
+                    'rrsig' : (RRSIG, {}), 'nsec' : (NSEC, {}),
+                    'nsec3' : (NSEC3, {}), 'tsig' : (TSIG, {}) }
+    s = section
+    m = re.match('^([^:]+)/\d+$', section)
+    if m:
+        s = m.group(1)
+    return config_param[s]
+
+usage = '''usage: %prog [options] input_file'''
+
+if __name__ == "__main__":
+    parser = OptionParser(usage=usage)
+    parser.add_option('-o', '--output', action='store', dest='output',
+                      default=None, metavar='FILE',
+                      help='output file name [default: prefix of input_file]')
+    (options, args) = parser.parse_args()
+
+    if len(args) == 0:
+        parser.error('input file is missing')
+    configfile = args[0]
+
+    outputfile = options.output
+    if not outputfile:
+        m = re.match('(.*)\.[^.]+$', configfile)
+        if m:
+            outputfile = m.group(1)
+        else:
+            raise ValueError('output file is not specified and input file is not in the form of "output_file.suffix"')
+
+    config = configparser.SafeConfigParser()
+    config.read(configfile)
+
+    output = open(outputfile, 'w')
+
+    print_header(output, configfile)
+
+    # First try the 'custom' mode; if it fails assume the standard mode.
+    try:
+        sections = config.get('custom', 'sections').split(':')
+    except configparser.NoSectionError:
+        sections = ['header', 'question', 'edns']
+
+    for s in sections:
+        section_param = get_config_param(s)
+        (obj, xtables) = (section_param[0](), section_param[1])
+        if get_config(config, s, obj, xtables):
+            obj.dump(output)
+
+    output.close()




More information about the bind10-changes mailing list