-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a function to extract all includes from bind configuration …
…file It should support chroot directories because we use chroot environment for bind configurations in plesk. Also we should not encounter relative paths in include directives because bind handles they in a preatty specific way (starting from the directory bind was started)
- Loading branch information
Mikhail Sandakov
committed
Oct 4, 2024
1 parent
2666d01
commit b9df963
Showing
3 changed files
with
205 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Copyright 2023-2024. WebPros International GmbH. All rights reserved. | ||
import os | ||
from typing import Deque, List | ||
from collections import deque | ||
|
||
from . import log | ||
|
||
|
||
def get_all_includes_from_bind_config(config_file: str, chroot_dir: str = "") -> List[str]: | ||
includes: List[str] = [] | ||
|
||
if os.path.isabs(config_file): | ||
config_file = chroot_dir + config_file | ||
else: | ||
config_file = os.path.join(chroot_dir, config_file) | ||
|
||
if not os.path.exists(config_file): | ||
return includes | ||
|
||
queue: Deque[str] = deque([config_file]) | ||
|
||
while queue: | ||
current_file = queue.popleft() | ||
if not os.path.exists(current_file): | ||
continue | ||
|
||
with open(current_file) as f: | ||
for line in f: | ||
line = line.strip() | ||
if line.startswith("include"): | ||
include_file = line.split('"')[1] | ||
|
||
if not os.path.isabs(include_file): | ||
log.warn(f"Relative include path directive {line!r} from {current_file!r} is not supported. Skipping.") | ||
continue | ||
|
||
include_file = chroot_dir + include_file | ||
|
||
includes.append(include_file) | ||
queue.append(include_file) | ||
|
||
return includes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# Copyright 2023-2024. WebPros International GmbH. All rights reserved. | ||
import shutil | ||
import os | ||
import unittest | ||
|
||
import src.dns as dns | ||
|
||
|
||
class TestGetIncludeFromBindConfiguration(unittest.TestCase): | ||
|
||
def tearDown(self): | ||
if os.path.exists("test.conf"): | ||
os.remove("test.conf") | ||
|
||
if os.path.exists("chroot"): | ||
shutil.rmtree("chroot") | ||
|
||
def test_no_config_file(self): | ||
with open("test.conf", "w") as test_bind_config: | ||
test_bind_config.write(''' | ||
options { | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
self.assertEqual(dns.get_all_includes_from_bind_config("nonexistent.conf"), []) | ||
|
||
def test_one_include(self): | ||
with open("test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included.conf"; | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
|
||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf"), ["/included.conf"]) | ||
|
||
def test_include_with_spaces(self): | ||
with open("test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included .conf" ; # comment | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf"), ["/included .conf"]) | ||
|
||
def test_include_with_tabs(self): | ||
with open("test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included .conf" ; | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf"), ["/included .conf"]) | ||
|
||
def test_multiple_includes(self): | ||
with open("test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included1.conf"; | ||
include "/included2.conf"; | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
|
||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf"), ["/included1.conf", "/included2.conf"]) | ||
|
||
def test_nested_includes(self): | ||
current_dir = os.getcwd() | ||
with open("test.conf", "w") as test_file: | ||
test_file.write(f''' | ||
options {{ | ||
include "{current_dir}/included1.conf"; | ||
include "{current_dir}/included2.conf"; | ||
allow-recursion {{ | ||
localnets; | ||
}}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}}; | ||
''') | ||
|
||
with open("included1.conf", "w") as test_file: | ||
test_file.write(f'include "{current_dir}/included3.conf";\n') | ||
|
||
with open("included2.conf", "w") as test_file: | ||
test_file.write(f'include "{current_dir}/included4.conf";\n') | ||
|
||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf"), [f"{current_dir}/included1.conf", | ||
f"{current_dir}/included2.conf", | ||
f"{current_dir}/included3.conf", | ||
f"{current_dir}/included4.conf"]) | ||
|
||
os.remove("included1.conf") | ||
os.remove("included2.conf") | ||
|
||
def test_chroot_with_absolute_path(self): | ||
os.makedirs("chroot", exist_ok=True) | ||
|
||
with open("chroot/test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included.conf"; | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
self.assertEqual(dns.get_all_includes_from_bind_config("/test.conf", chroot_dir="chroot"), ["chroot/included.conf"]) | ||
|
||
def test_nested_includes_with_chroot(self): | ||
os.makedirs("chroot", exist_ok=True) | ||
|
||
with open("chroot/test.conf", "w") as test_file: | ||
test_file.write(''' | ||
options { | ||
include "/included1.conf"; | ||
include "/included2.conf"; | ||
allow-recursion { | ||
localnets; | ||
}; | ||
directory "/var"; | ||
pid-file "/var/run/named/named.pid"; | ||
}; | ||
''') | ||
|
||
with open("chroot/included1.conf", "w") as test_file: | ||
test_file.write('include "/subdir/included3.conf";\n') | ||
|
||
with open("chroot/included2.conf", "w") as test_file: | ||
test_file.write('include "/subdir/included4.conf";\n') | ||
|
||
self.assertEqual(dns.get_all_includes_from_bind_config("test.conf", chroot_dir="chroot"), [ | ||
"chroot/included1.conf", | ||
"chroot/included2.conf", | ||
"chroot/subdir/included3.conf", | ||
"chroot/subdir/included4.conf" | ||
]) |