Exemple #1
0
    def test_parse_then_make_then_parse_generates_identical_config(self):
        testdata = dedent("""\
            acl canonical-int-ns { 91.189.90.151; 91.189.89.192;  };

            options {
                directory "/var/cache/bind";

                forwarders {
                    91.189.94.2;
                    91.189.94.2;
                };

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };

                allow-query { any; };
                allow-transfer { 10.222.64.1; canonical-int-ns; };

                notify explicit;
                also-notify { 91.189.90.151; 91.189.89.192;  };

                allow-query-cache { 10.222.64.0/18; };
                recursion yes;
            };

            zone "."  { type master; file "/etc/bind/db.special"; };
            """)
        config = parse_isc_string(testdata)
        config_string = make_isc_string(config)
        config = parse_isc_string(config_string)
        self.assertEqual(
            OrderedDict([('acl canonical-int-ns',
                          OrderedDict([('91.189.90.151', True),
                                       ('91.189.89.192', True)])),
                         ('options',
                          OrderedDict([
                              ('directory', '"/var/cache/bind"'),
                              ('forwarders',
                               OrderedDict([('91.189.94.2', True)])),
                              ('dnssec-validation', 'auto'),
                              ('auth-nxdomain', 'no'),
                              ('listen-on-v6', OrderedDict([('any', True)])),
                              ('allow-query', OrderedDict([('any', True)])),
                              ('allow-transfer',
                               OrderedDict([('10.222.64.1', True),
                                            ('canonical-int-ns', True)])),
                              ('notify', 'explicit'),
                              ('also-notify',
                               OrderedDict([('91.189.90.151', True),
                                            ('91.189.89.192', True)])),
                              ('allow-query-cache',
                               OrderedDict([('10.222.64.0/18', True)])),
                              ('recursion', 'yes')
                          ])),
                         ('zone "."',
                          OrderedDict([('type', 'master'),
                                       ('file', '"/etc/bind/db.special"')]))]),
            config)
Exemple #2
0
def edit_options(config_path,
                 stdout=sys.stdout,
                 dry_run=False,
                 force=False,
                 options_handler=None):
    """
    Edit the named.conf.options file so that it includes the
    named.conf.options.inside.maas file.
    """
    options_file = read_file(config_path)
    config_dict = parse_file(config_path, options_file)
    original_config = deepcopy(config_dict)

    options_block = config_dict['options']

    # Modify the configuration (if necessary).
    set_up_include_statement(options_block, config_path)

    # Options handler that can modify the options block more.
    if options_handler is not None:
        options_handler(options_block)

    # Re-parse the new configuration, so we can detect any changes.
    new_content = make_isc_string(config_dict)
    new_config = parse_isc_string(new_content)
    if original_config != new_config or force:
        # The configuration has changed. Back up and write new file.
        if dry_run:
            write_new_named_conf_options(stdout, config_path, new_content)
        else:
            backup_filename = back_up_existing_file(config_path)
            with open(config_path, "w", encoding="ascii") as fd:
                write_new_named_conf_options(fd, backup_filename, new_content)
Exemple #3
0
 def test_parser_preserves_order(self):
     testdata = dedent("""\
         forwarders {
             9.9.9.9;
             8.8.8.8;
             7.7.7.7;
             6.6.6.6;
             5.5.5.5;
             4.4.4.4;
             3.3.3.3;
             2.2.2.2;
             1.1.1.1;
         };
         """)
     forwarders = parse_isc_string(testdata)
     self.assertEqual(
         OrderedDict([(
             "forwarders",
             OrderedDict([
                 ("9.9.9.9", True),
                 ("8.8.8.8", True),
                 ("7.7.7.7", True),
                 ("6.6.6.6", True),
                 ("5.5.5.5", True),
                 ("4.4.4.4", True),
                 ("3.3.3.3", True),
                 ("2.2.2.2", True),
                 ("1.1.1.1", True),
             ]),
         )]),
         forwarders,
     )
    def test_dry_run_migrates_nothing_and_prints_config(self):
        options_file = self.make_file(
            contents=OPTIONS_FILE_WITH_FORWARDERS_AND_DNSSEC)
        call_command(
            "edit_named_options", config_path=options_file,
            migrate_conflicting_options=True, dry_run=True, stdout=self.stdout)

        upstream_dns = get_one(Config.objects.filter(name="upstream_dns"))
        self.assertIsNone(upstream_dns)
        dnssec_validation = get_one(Config.objects.filter(
            name="dnssec_validation"))
        self.assertIsNone(dnssec_validation)

        # Check that a proper configuration was written to stdout.
        config = parse_isc_string(self.stdout.getvalue())
        self.assertIsNotNone(config)
Exemple #5
0
 def test_parses_bind_acl(self):
     testdata = dedent("""\
         acl goodclients {
             192.0.2.0/24;
             localhost;
             localnets;
         };
         """)
     acl = parse_isc_string(testdata)
     self.assertEqual(
         {
             'acl goodclients': {
                 '192.0.2.0/24': True,
                 'localhost': True,
                 'localnets': True,
             }
         }, acl)
Exemple #6
0
    def parse_file(self, config_path, options_file):
        """Read the named.conf.options file and parse it.

        Then insert the include statement that we need.
        """
        try:
            config_dict = parse_isc_string(options_file)
        except ISCParseException as e:
            raise CommandError("Failed to parse %s: %s" %
                               (config_path, str(e))) from e
        options_block = config_dict.get("options", None)
        if options_block is None:
            # Something is horribly wrong with the file; bail out rather
            # than doing anything drastic.
            raise CommandError(
                "Can't find options {} block in %s, bailing out without "
                "doing anything." % config_path)
        return config_dict
Exemple #7
0
 def test_write_config_with_forwarded_zones(self):
     name = factory.make_name("domain")
     ip = factory.make_ip_address()
     forwarded_zones = [(name, [ip])]
     target_dir = patch_dns_config_path(self)
     DNSConfig(forwarded_zones=forwarded_zones).write_config()
     config_path = os.path.join(target_dir, MAAS_NAMED_CONF_NAME)
     expected_content = dedent(f"""
     zone "{name}" {{
         type forward;
         forward only;
         forwarders {{
             {ip};
         }};
     }};
     """)
     config = read_isc_file(config_path)
     expected = parse_isc_string(expected_content)
     self.assertEqual(expected[f'zone "{name}"'], config[f'zone "{name}"'])
Exemple #8
0
 def test_parses_bind_acl(self):
     testdata = dedent("""\
         acl goodclients {
             192.0.2.0/24;
             localhost;
             localnets;
         };
         """)
     acl = parse_isc_string(testdata)
     self.assertEqual(
         {
             "acl goodclients": {
                 "192.0.2.0/24": True,
                 "localhost": True,
                 "localnets": True,
             }
         },
         acl,
     )
Exemple #9
0
 def test_parses_multiple_forwarders(self):
     testdata = dedent("""\
         forwarders {
             91.189.94.2;
             91.189.94.3;
             91.189.94.4;
             91.189.94.5;
             91.189.94.6;
         };
         """)
     forwarders = parse_isc_string(testdata)
     self.assertEqual(
         {
             'forwarders': {
                 '91.189.94.2': True,
                 '91.189.94.3': True,
                 '91.189.94.4': True,
                 '91.189.94.5': True,
                 '91.189.94.6': True,
             }
         }, forwarders)
Exemple #10
0
    def handle(self, *args, **options):
        """Entry point for BaseCommand."""
        # Read stuff in, validate.
        config_path = options.get('config_path')
        dry_run = options.get('dry_run')
        force = options.get('force')
        stdout = options.get('stdout')
        if stdout is None:
            stdout = sys.stdout
        migrate_conflicting_options = options.get(
            'migrate_conflicting_options')

        options_file = self.read_file(config_path)
        config_dict = self.parse_file(config_path, options_file)
        original_config = deepcopy(config_dict)

        options_block = config_dict['options']

        # Modify the configuration (if necessary).
        self.set_up_include_statement(options_block, config_path)

        if migrate_conflicting_options:
            self.migrate_forwarders(options_block, dry_run, stdout)
            self.migrate_dnssec_validation(options_block, dry_run, stdout)

        # Re-parse the new configuration, so we can detect any changes.
        new_content = make_isc_string(config_dict)
        new_config = parse_isc_string(new_content)

        if original_config != new_config or force:
            # The configuration has changed. Back up and write new file.
            if dry_run:
                self.write_new_named_conf_options(stdout, config_path,
                                                  new_content)
            else:
                backup_filename = self.back_up_existing_file(config_path)
                with open(config_path, "w", encoding="ascii") as fd:
                    self.write_new_named_conf_options(fd, backup_filename,
                                                      new_content)
Exemple #11
0
    def test_parses_simple_bind_options(self):
        testdata = dedent("""\
            options {
                directory "/var/cache/bind";

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };
            };
            """)
        options = parse_isc_string(testdata)
        self.assertEqual(
            OrderedDict([
                ('options',
                 OrderedDict([
                     ('directory', '"/var/cache/bind"'),
                     ('dnssec-validation', 'auto'),
                     ('auth-nxdomain', 'no'),
                     ('listen-on-v6', OrderedDict([('any', True)])),
                 ])),
            ]), options)
Exemple #12
0
 def test_parser_preserves_order(self):
     testdata = dedent("""\
         forwarders {
             9.9.9.9;
             8.8.8.8;
             7.7.7.7;
             6.6.6.6;
             5.5.5.5;
             4.4.4.4;
             3.3.3.3;
             2.2.2.2;
             1.1.1.1;
         };
         """)
     forwarders = parse_isc_string(testdata)
     self.assertEqual(
         OrderedDict([('forwarders',
                       OrderedDict([('9.9.9.9', True), ('8.8.8.8', True),
                                    ('7.7.7.7', True), ('6.6.6.6', True),
                                    ('5.5.5.5', True), ('4.4.4.4', True),
                                    ('3.3.3.3', True), ('2.2.2.2', True),
                                    ('1.1.1.1', True)]))]), forwarders)
Exemple #13
0
 def test_parses_multiple_forwarders(self):
     testdata = dedent("""\
         forwarders {
             91.189.94.2;
             91.189.94.3;
             91.189.94.4;
             91.189.94.5;
             91.189.94.6;
         };
         """)
     forwarders = parse_isc_string(testdata)
     self.assertEqual(
         {
             "forwarders": {
                 "91.189.94.2": True,
                 "91.189.94.3": True,
                 "91.189.94.4": True,
                 "91.189.94.5": True,
                 "91.189.94.6": True,
             }
         },
         forwarders,
     )
Exemple #14
0
    def test_parses_simple_bind_options(self):
        testdata = dedent("""\
            options {
                directory "/var/cache/bind";

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };
            };
            """)
        options = parse_isc_string(testdata)
        self.assertEqual(
            OrderedDict([(
                "options",
                OrderedDict([
                    ("directory", '"/var/cache/bind"'),
                    ("dnssec-validation", "auto"),
                    ("auth-nxdomain", "no"),
                    ("listen-on-v6", OrderedDict([("any", True)])),
                ]),
            )]),
            options,
        )
Exemple #15
0
    def test_parses_bug_1413388_config(self):
        testdata = dedent("""\
            acl canonical-int-ns { 91.189.90.151; 91.189.89.192;  };

            options {
                directory "/var/cache/bind";

                forwarders {
                    91.189.94.2;
                    91.189.94.2;
                };

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };

                allow-query { any; };
                allow-transfer { 10.222.64.1; canonical-int-ns; };

                notify explicit;
                also-notify { 91.189.90.151; 91.189.89.192;  };

                allow-query-cache { 10.222.64.0/18; };
                recursion yes;
            };

            zone "."  { type master; file "/etc/bind/db.special"; };
            """)
        config = parse_isc_string(testdata)
        self.assertEqual(
            {
                "acl canonical-int-ns": {
                    "91.189.89.192": True,
                    "91.189.90.151": True,
                },
                "options": {
                    "allow-query": {
                        "any": True
                    },
                    "allow-query-cache": {
                        "10.222.64.0/18": True
                    },
                    "allow-transfer": {
                        "10.222.64.1": True,
                        "canonical-int-ns": True,
                    },
                    "also-notify": {
                        "91.189.89.192": True,
                        "91.189.90.151": True,
                    },
                    "auth-nxdomain": "no",
                    "directory": '"/var/cache/bind"',
                    "dnssec-validation": "auto",
                    "forwarders": {
                        "91.189.94.2": True
                    },
                    "listen-on-v6": {
                        "any": True
                    },
                    "notify": "explicit",
                    "recursion": "yes",
                },
                'zone "."': {
                    "file": '"/etc/bind/db.special"',
                    "type": "master",
                },
            },
            config,
        )
Exemple #16
0
 def test_parse_forgotten_semicolons_throw_iscparseexception(self):
     with ExpectedException(ISCParseException):
         parse_isc_string("a { b; } { c; } d e;")
Exemple #17
0
 def test_parse_malformed_list_throws_iscparseexception(self):
     with ExpectedException(ISCParseException):
         parse_isc_string("forwarders {{}a;;b}")
Exemple #18
0
 def test_parse_unmatched_brackets_throws_iscparseexception(self):
     with ExpectedException(ISCParseException):
         parse_isc_string("forwarders {")
Exemple #19
0
    def test_parse_then_make_then_parse_generates_identical_config(self):
        testdata = dedent("""\
            acl canonical-int-ns { 91.189.90.151; 91.189.89.192;  };

            options {
                directory "/var/cache/bind";

                forwarders {
                    91.189.94.2;
                    91.189.94.2;
                };

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };

                allow-query { any; };
                allow-transfer { 10.222.64.1; canonical-int-ns; };

                notify explicit;
                also-notify { 91.189.90.151; 91.189.89.192;  };

                allow-query-cache { 10.222.64.0/18; };
                recursion yes;
            };

            zone "."  { type master; file "/etc/bind/db.special"; };
            """)
        config = parse_isc_string(testdata)
        config_string = make_isc_string(config)
        config = parse_isc_string(config_string)
        self.assertEqual(
            OrderedDict([
                (
                    "acl canonical-int-ns",
                    OrderedDict([("91.189.90.151", True),
                                 ("91.189.89.192", True)]),
                ),
                (
                    "options",
                    OrderedDict([
                        ("directory", '"/var/cache/bind"'),
                        (
                            "forwarders",
                            OrderedDict([("91.189.94.2", True)]),
                        ),
                        ("dnssec-validation", "auto"),
                        ("auth-nxdomain", "no"),
                        ("listen-on-v6", OrderedDict([("any", True)])),
                        ("allow-query", OrderedDict([("any", True)])),
                        (
                            "allow-transfer",
                            OrderedDict([
                                ("10.222.64.1", True),
                                ("canonical-int-ns", True),
                            ]),
                        ),
                        ("notify", "explicit"),
                        (
                            "also-notify",
                            OrderedDict([
                                ("91.189.90.151", True),
                                ("91.189.89.192", True),
                            ]),
                        ),
                        (
                            "allow-query-cache",
                            OrderedDict([("10.222.64.0/18", True)]),
                        ),
                        ("recursion", "yes"),
                    ]),
                ),
                (
                    'zone "."',
                    OrderedDict([
                        ("type", "master"),
                        ("file", '"/etc/bind/db.special"'),
                    ]),
                ),
            ]),
            config,
        )
Exemple #20
0
    def test_parses_bug_1413388_config(self):
        testdata = dedent("""\
            acl canonical-int-ns { 91.189.90.151; 91.189.89.192;  };

            options {
                directory "/var/cache/bind";

                forwarders {
                    91.189.94.2;
                    91.189.94.2;
                };

                dnssec-validation auto;

                auth-nxdomain no;    # conform to RFC1035
                listen-on-v6 { any; };

                allow-query { any; };
                allow-transfer { 10.222.64.1; canonical-int-ns; };

                notify explicit;
                also-notify { 91.189.90.151; 91.189.89.192;  };

                allow-query-cache { 10.222.64.0/18; };
                recursion yes;
            };

            zone "."  { type master; file "/etc/bind/db.special"; };
            """)
        config = parse_isc_string(testdata)
        self.assertEqual(
            {
                'acl canonical-int-ns': {
                    '91.189.89.192': True,
                    '91.189.90.151': True,
                },
                'options': {
                    'allow-query': {
                        'any': True
                    },
                    'allow-query-cache': {
                        '10.222.64.0/18': True
                    },
                    'allow-transfer': {
                        '10.222.64.1': True,
                        'canonical-int-ns': True,
                    },
                    'also-notify': {
                        '91.189.89.192': True,
                        '91.189.90.151': True,
                    },
                    'auth-nxdomain': 'no',
                    'directory': '"/var/cache/bind"',
                    'dnssec-validation': 'auto',
                    'forwarders': {
                        '91.189.94.2': True
                    },
                    'listen-on-v6': {
                        'any': True
                    },
                    'notify': 'explicit',
                    'recursion': 'yes'
                },
                'zone "."': {
                    'file': '"/etc/bind/db.special"',
                    'type': 'master',
                }
            }, config)