Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hostname plugin for RedHat systems #513

Merged
merged 10 commits into from
Jan 31, 2024
36 changes: 27 additions & 9 deletions dissect/target/plugins/os/unix/_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,28 +132,46 @@ def domain(self) -> Optional[str]:
def os(self) -> str:
return OperatingSystem.UNIX.value

def _parse_rh_legacy(self, path):
hostname = None
file_contents = path.open("rt").readlines()
for line in file_contents:
if not line.startswith("HOSTNAME"):
continue
_, _, hostname = line.rstrip().partition("=")
return hostname

def _parse_hostname_string(self, paths: Optional[list[str]] = None) -> Optional[dict[str, str]]:
"""
Returns a dict with containing the hostname and domain name portion of the path(s) specified
Returns a dict containing the hostname and domain name portion of the path(s) specified

Args:
paths (list): list of paths
"""
paths = paths or ["/etc/hostname", "/etc/HOSTNAME"]
hostname_string = None
redhat_legacy_path = "/etc/sysconfig/network"
paths = paths or ["/etc/hostname", "/etc/HOSTNAME", redhat_legacy_path]
hostname_dict = {"hostname": None, "domain": None}

for path in paths:
for fs in self.target.filesystems:
if fs.exists(path):
hostname_string = fs.path(path).open("rt").read().rstrip()
path = self.target.fs.path(path)

if not path.exists():
continue

if path.as_posix() == redhat_legacy_path:
hostname_string = self._parse_rh_legacy(path)
else:
hostname_string = path.open("rt").read().rstrip()

if hostname_string and "." in hostname_string:
hostname_string = hostname_string.split(".", maxsplit=1)
hostname_dict = {"hostname": hostname_string[0], "domain": hostname_string[1]}
else:
elif hostname_string != "":
hostname_dict = {"hostname": hostname_string, "domain": None}

return hostname_dict
else:
hostname_dict = {"hostname": None, "domain": None}
break # break whenever a valid hostname is found
return hostname_dict

def _parse_hosts_string(self, paths: Optional[list[str]] = None) -> dict[str, str]:
paths = paths or ["/etc/hosts"]
Expand Down
39 changes: 39 additions & 0 deletions tests/plugins/os/unix/test__os.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import tempfile
from io import BytesIO
from pathlib import Path
from uuid import UUID

import pytest

from dissect.target.filesystem import VirtualFilesystem
from dissect.target.plugins.os.unix._os import parse_fstab
from dissect.target.target import Target

FSTAB_CONTENT = """
# /etc/fstab: static file system information.
Expand Down Expand Up @@ -61,3 +66,37 @@ def test_parse_fstab(tmp_path):
(None, "vg--main-lv--var", "/var", "auto", "default"),
(None, "vg--main-lv--data", "/data", "auto", "default"),
}


@pytest.mark.parametrize(
"path, expected_hostname, expected_domain, file_content",
[
("/etc/hostname", "myhost", "mydomain.com", "myhost.mydomain.com"),
("/etc/HOSTNAME", "myhost", "mydomain.com", "myhost.mydomain.com"),
(
"/etc/sysconfig/network",
"myhost",
"mydomain.com",
"NETWORKING=NO\nHOSTNAME=myhost.mydomain.com\nGATEWAY=192.168.1.1",
),
("/etc/hostname", "myhost", None, "myhost"),
("/etc/sysconfig/network", "myhost", None, "NETWORKING=NO\nHOSTNAME=myhost\nGATEWAY=192.168.1.1"),
("/not_a_valid_hostname_path", None, None, ""),
("/etc/hostname", None, None, ""),
("/etc/sysconfig/network", None, None, ""),
],
)
def test__parse_hostname_string(
target_unix: Target,
fs_unix: VirtualFilesystem,
path: Path,
expected_hostname: str,
expected_domain: str,
file_content: str,
) -> None:
fs_unix.map_file_fh(path, BytesIO(file_content.encode("ascii")))

hostname_dict = target_unix._os._parse_hostname_string()

assert hostname_dict["hostname"] == expected_hostname
assert hostname_dict["domain"] == expected_domain
Loading