dissect.target 3.20.dev64__py3-none-any.whl → 3.21.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,338 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from dataclasses import dataclass, field
5
+ from datetime import datetime, timezone
6
+ from ipaddress import ip_address, ip_interface
7
+ from typing import TYPE_CHECKING, Any, Iterator, Literal, NamedTuple
8
+
9
+ from dissect.target.helpers import configutil
10
+ from dissect.target.helpers.record import UnixInterfaceRecord
11
+ from dissect.target.helpers.utils import to_list
12
+ from dissect.target.plugins.general.network import NetworkPlugin
13
+
14
+ if TYPE_CHECKING:
15
+ from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
16
+
17
+ from dissect.target import Target
18
+ from dissect.target.target import TargetPath
19
+
20
+ NetAddress = IPv4Address | IPv6Address
21
+ NetInterface = IPv4Interface | IPv6Interface
22
+
23
+
24
+ class LinuxNetworkPlugin(NetworkPlugin):
25
+ """Linux network interface plugin."""
26
+
27
+ def _interfaces(self) -> Iterator[UnixInterfaceRecord]:
28
+ """Try all available network configuration managers and aggregate the results."""
29
+ for manager_cls in MANAGERS:
30
+ manager: LinuxNetworkConfigParser = manager_cls(self.target)
31
+ yield from manager.interfaces()
32
+
33
+
34
+ VlanIdByInterface = dict[str, set[int]]
35
+
36
+
37
+ class LinuxNetworkConfigParser:
38
+ def __init__(self, target: Target):
39
+ self._target = target
40
+
41
+ def _config_files(self, config_paths: list[str], glob: str) -> list[TargetPath]:
42
+ """Returns all configuration files in config_paths matching the given extension."""
43
+ all_files = []
44
+ for config_path in config_paths:
45
+ paths = self._target.fs.path(config_path).glob(glob)
46
+ all_files.extend(config_file for config_file in paths if config_file.is_file())
47
+
48
+ return sorted(all_files, key=lambda p: p.stem)
49
+
50
+ def interfaces(self) -> Iterator[UnixInterfaceRecord]:
51
+ """Parse network interfaces from configuration files."""
52
+ yield from ()
53
+
54
+
55
+ class NetworkManagerConfigParser(LinuxNetworkConfigParser):
56
+ """NetworkManager configuration parser.
57
+
58
+ NetworkManager configuration files are generally in an INI-like format.
59
+ Note that Red Hat and Fedora deprecated ifcfg files.
60
+ Documentation: https://networkmanager.dev/docs/api/latest/nm-settings-keyfile.html
61
+ """
62
+
63
+ config_paths: list[str] = [
64
+ "/etc/NetworkManager/system-connections/",
65
+ "/usr/lib/NetworkManager/system-connections/",
66
+ "/run/NetworkManager/system-connections/",
67
+ ]
68
+
69
+ @dataclass
70
+ class ParserContext:
71
+ source: str
72
+ uuid: str | None = None
73
+ last_connected: datetime | None = None
74
+ name: str | None = None
75
+ mac_address: str | None = None
76
+ type: str = ""
77
+ dns: set[NetAddress] = field(default_factory=set)
78
+ ip_interfaces: set[NetInterface] = field(default_factory=set)
79
+ gateways: set[NetAddress] = field(default_factory=set)
80
+ dhcp_ipv4: bool = False
81
+ dhcp_ipv6: bool = False
82
+ vlan: set[int] = field(default_factory=set)
83
+
84
+ def to_record(self) -> UnixInterfaceRecord:
85
+ return UnixInterfaceRecord(
86
+ source=self.source,
87
+ last_connected=self.last_connected,
88
+ name=self.name,
89
+ mac=[self.mac_address] if self.mac_address else [],
90
+ type=self.type,
91
+ dhcp_ipv4=self.dhcp_ipv4,
92
+ dhcp_ipv6=self.dhcp_ipv6,
93
+ dns=list(self.dns),
94
+ ip=[interface.ip for interface in self.ip_interfaces],
95
+ network=[interface.network for interface in self.ip_interfaces],
96
+ gateway=list(self.gateways),
97
+ vlan=list(self.vlan),
98
+ configurator="NetworkManager",
99
+ )
100
+
101
+ def interfaces(self) -> Iterator[UnixInterfaceRecord]:
102
+ connections: list[NetworkManagerConfigParser.ParserContext] = []
103
+ vlan_id_by_interface: VlanIdByInterface = {}
104
+
105
+ for connection_file_path in self._config_files(self.config_paths, "*"):
106
+ try:
107
+ config = configutil.parse(connection_file_path, hint="ini")
108
+ context = self.ParserContext(source=connection_file_path)
109
+ common_section: dict[str, str] = config.get("connection", {})
110
+ context.type = common_section.get("type", "")
111
+ sub_type: dict[str, str] = config.get(context.type, {})
112
+
113
+ if context.type == "vlan":
114
+ self._parse_vlan(sub_type, vlan_id_by_interface)
115
+ continue
116
+
117
+ for ip_version in ["ipv4", "ipv6"]:
118
+ ip_section: dict[str, str] = config.get(ip_version, {})
119
+ for key, value in ip_section.items():
120
+ self._parse_ip_section_key(key, value, context, ip_version)
121
+
122
+ context.name = common_section.get("interface-name")
123
+ context.mac_address = sub_type.get("mac-address")
124
+ context.uuid = common_section.get("uuid")
125
+ context.source = str(connection_file_path)
126
+ context.last_connected = self._parse_lastconnected(common_section.get("timestamp", ""))
127
+
128
+ connections.append(context)
129
+
130
+ except Exception as e:
131
+ self._target.log.warning("Error parsing network config file %s", connection_file_path)
132
+ self._target.log.debug("", exc_info=e)
133
+
134
+ for connection in connections:
135
+ vlan_ids_from_interface = vlan_id_by_interface.get(connection.name, set())
136
+ connection.vlan.update(vlan_ids_from_interface)
137
+
138
+ vlan_ids_from_uuid = vlan_id_by_interface.get(connection.uuid, set())
139
+ connection.vlan.update(vlan_ids_from_uuid)
140
+
141
+ yield connection.to_record()
142
+
143
+ def _parse_route(self, route: str) -> NetAddress | None:
144
+ """Parse a route and return gateway IP address."""
145
+ if (elements := route.split(",")) and len(elements) > 1:
146
+ return ip_address(elements[1])
147
+
148
+ return None
149
+
150
+ def _parse_lastconnected(self, last_connected: str) -> datetime | None:
151
+ """Parse last connected timestamp."""
152
+ if not last_connected:
153
+ return None
154
+
155
+ return datetime.fromtimestamp(int(last_connected), timezone.utc)
156
+
157
+ def _parse_ip_section_key(
158
+ self, key: str, value: str, context: ParserContext, ip_version: Literal["ipv4", "ipv6"]
159
+ ) -> None:
160
+ if not (trimmed := value.strip()):
161
+ return
162
+
163
+ if key == "dns":
164
+ context.dns.update(ip_address(addr) for addr in trimmed.split(";") if addr)
165
+ elif key.startswith("address"):
166
+ # Undocumented: single gateway on address line. Observed when running:
167
+ # nmcli connection add type ethernet ... ip4 192.168.2.138/24 gw4 192.168.2.1
168
+ ip, *gateway = trimmed.split(",", 1)
169
+ context.ip_interfaces.add(ip_interface(ip))
170
+ if gateway:
171
+ context.gateways.add(ip_address(gateway[0]))
172
+ elif key.startswith("gateway"):
173
+ context.gateways.add(ip_address(trimmed))
174
+ elif key == "method":
175
+ if ip_version == "ipv4":
176
+ context.dhcp_ipv4 = trimmed == "auto"
177
+ elif ip_version == "ipv6":
178
+ context.dhcp_ipv6 = trimmed == "auto"
179
+ elif key.startswith("route"):
180
+ if gateway := self._parse_route(value):
181
+ context.gateways.add(gateway)
182
+
183
+ def _parse_vlan(self, sub_type: dict[str, Any], vlan_id_by_interface: VlanIdByInterface) -> None:
184
+ parent_interface = sub_type.get("parent")
185
+ vlan_id = sub_type.get("id")
186
+ if not parent_interface or not vlan_id:
187
+ return
188
+
189
+ ids = vlan_id_by_interface.setdefault(parent_interface, set())
190
+ ids.add(int(vlan_id))
191
+
192
+
193
+ class SystemdNetworkConfigParser(LinuxNetworkConfigParser):
194
+ """Systemd network configuration parser.
195
+
196
+ Systemd network configuration files are generally in an INI-like format with some quirks.
197
+ Note that drop-in directories are not yet supported.
198
+
199
+ Documentation: https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html
200
+ """
201
+
202
+ config_paths: list[str] = [
203
+ "/etc/systemd/network/",
204
+ "/run/systemd/network/",
205
+ "/usr/lib/systemd/network/",
206
+ "/usr/local/lib/systemd/network/",
207
+ ]
208
+
209
+ class DhcpConfig(NamedTuple):
210
+ ipv4: bool
211
+ ipv6: bool
212
+
213
+ # Can be enclosed in brackets for IPv6. Can also have port, iface name, and SNI, which we ignore.
214
+ # Example: [1111:2222::3333]:9953%ifname#example.com
215
+ dns_ip_patttern = re.compile(
216
+ r"(?P<withoutBrackets>(?:\d{1,3}\.){3}\d{1,3})|\[(?P<withBrackets>\[?[0-9a-fA-F:]+\]?)\]"
217
+ )
218
+
219
+ def interfaces(self) -> Iterator:
220
+ virtual_networks = self._parse_virtual_networks()
221
+ yield from self._parse_networks(virtual_networks)
222
+
223
+ def _parse_virtual_networks(self) -> VlanIdByInterface:
224
+ """Parse virtual network configurations from systemd network configuration files."""
225
+
226
+ virtual_networks: VlanIdByInterface = {}
227
+ for config_file in self._config_files(self.config_paths, "*.netdev"):
228
+ try:
229
+ virtual_network_config = configutil.parse(config_file, hint="systemd")
230
+ net_dev_section: dict[str, str] = virtual_network_config.get("NetDev", {})
231
+ if net_dev_section.get("Kind") != "vlan":
232
+ continue
233
+
234
+ vlan_id = virtual_network_config.get("VLAN", {}).get("Id")
235
+ if (name := net_dev_section.get("Name")) and vlan_id:
236
+ vlan_ids = virtual_networks.setdefault(name, set())
237
+ vlan_ids.add(int(vlan_id))
238
+ except Exception as e:
239
+ self._target.log.warning("Error parsing virtual network config file %s", config_file)
240
+ self._target.log.debug("", exc_info=e)
241
+
242
+ return virtual_networks
243
+
244
+ def _parse_networks(self, virtual_networks: VlanIdByInterface) -> Iterator[UnixInterfaceRecord]:
245
+ """Parse network configurations from systemd network configuration files."""
246
+ for config_file in self._config_files(self.config_paths, "*.network"):
247
+ try:
248
+ config = configutil.parse(config_file, hint="systemd")
249
+
250
+ match_section: dict[str, str] = config.get("Match", {})
251
+ network_section: dict[str, str] = config.get("Network", {})
252
+ link_section: dict[str, str] = config.get("Link", {})
253
+
254
+ ip_interfaces: set[NetInterface] = set()
255
+ gateways: set[NetAddress] = set()
256
+ dns: set[NetAddress] = set()
257
+ mac_addresses: set[str] = set()
258
+
259
+ if link_mac := link_section.get("MACAddress"):
260
+ mac_addresses.add(link_mac)
261
+ mac_addresses.update(match_section.get("MACAddress", "").split())
262
+ mac_addresses.update(match_section.get("PermanentMACAddress", "").split())
263
+
264
+ dns_value = to_list(network_section.get("DNS", []))
265
+ dns.update(self._parse_dns_ip(dns_ip) for dns_ip in dns_value)
266
+
267
+ address_value = to_list(network_section.get("Address", []))
268
+ ip_interfaces.update(ip_interface(addr) for addr in address_value)
269
+
270
+ gateway_value = to_list(network_section.get("Gateway", []))
271
+ gateways.update(ip_address(gateway) for gateway in gateway_value)
272
+
273
+ vlan_ids: set[int] = set()
274
+ vlan_names = to_list(network_section.get("VLAN", []))
275
+ for vlan_name in vlan_names:
276
+ if ids := virtual_networks.get(vlan_name):
277
+ vlan_ids.update(ids)
278
+
279
+ # There are possibly multiple route sections, but they are collapsed into one by the parser.
280
+ route_section: dict[str, Any] = config.get("Route", {})
281
+ gateway_values = to_list(route_section.get("Gateway", []))
282
+ gateways.update(filter(None, map(self._parse_gateway, gateway_values)))
283
+
284
+ dhcp_ipv4, dhcp_ipv6 = self._parse_dhcp(network_section.get("DHCP"))
285
+
286
+ yield UnixInterfaceRecord(
287
+ source=str(config_file),
288
+ type=match_section.get("Type"),
289
+ enabled=None, # Unknown, dependent on run-time state
290
+ dhcp_ipv4=dhcp_ipv4,
291
+ dhcp_ipv6=dhcp_ipv6,
292
+ name=match_section.get("Name"),
293
+ dns=list(dns),
294
+ mac=list(mac_addresses),
295
+ ip=[interface.ip for interface in ip_interfaces],
296
+ network=[interface.network for interface in ip_interfaces],
297
+ gateway=list(gateways),
298
+ vlan=list(vlan_ids),
299
+ configurator="systemd-networkd",
300
+ )
301
+ except Exception as e:
302
+ self._target.log.warning("Error parsing network config file %s", config_file)
303
+ self._target.log.debug("", exc_info=e)
304
+
305
+ def _parse_dns_ip(self, address: str) -> NetAddress:
306
+ """Parse DNS address from systemd network configuration file.
307
+
308
+ The optional brackets and port number make this hard to parse.
309
+ See https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html and search for DNS.
310
+ """
311
+
312
+ if match := self.dns_ip_patttern.search(address):
313
+ return ip_address(match.group("withoutBrackets") or match.group("withBrackets"))
314
+
315
+ raise ValueError(f"Invalid DNS address format: {address}")
316
+
317
+ def _parse_dhcp(self, value: str | None) -> DhcpConfig:
318
+ """Parse DHCP value from systemd network configuration file to a named tuple (ipv4, ipv6)."""
319
+
320
+ if value is None or value == "no":
321
+ return self.DhcpConfig(ipv4=False, ipv6=False)
322
+ elif value == "yes":
323
+ return self.DhcpConfig(ipv4=True, ipv6=True)
324
+ elif value == "ipv4":
325
+ return self.DhcpConfig(ipv4=True, ipv6=False)
326
+ elif value == "ipv6":
327
+ return self.DhcpConfig(ipv4=False, ipv6=True)
328
+
329
+ raise ValueError(f"Invalid DHCP value: {value}")
330
+
331
+ def _parse_gateway(self, value: str | None) -> NetAddress | None:
332
+ if (not value) or (value in {"_dhcp4", "_ipv6ra"}):
333
+ return None
334
+
335
+ return ip_address(value)
336
+
337
+
338
+ MANAGERS = [NetworkManagerConfigParser, SystemdNetworkConfigParser]
@@ -281,7 +281,8 @@ class WindowsNetworkPlugin(NetworkPlugin):
281
281
  pass
282
282
 
283
283
  # Extract the rest of the device information
284
- device_info["mac"] = _try_value(subkey, "NetworkAddress")
284
+ if mac_address := _try_value(subkey, "NetworkAddress"):
285
+ device_info["mac"] = [mac_address]
285
286
  device_info["vlan"] = _try_value(subkey, "VlanID")
286
287
 
287
288
  if timestamp := _try_value(subkey, "NetworkInterfaceInstallTimestamp"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.20.dev64
3
+ Version: 3.21.dev2
4
4
  Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -46,7 +46,7 @@ dissect/target/filesystems/zip.py,sha256=BeNj23DOYfWuTm5V1V419ViJiMfBrO1VA5gP6rl
46
46
  dissect/target/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  dissect/target/helpers/cache.py,sha256=TXlJBdFRz6V9zKs903am4Yawr0maYw5kZY0RqklDQJM,8568
48
48
  dissect/target/helpers/config.py,sha256=RMHnIuKJHINHiLrvKN3EyA0jFA1o6-pbeaycG8Pgrp8,2596
49
- dissect/target/helpers/configutil.py,sha256=KuuQoJZMr69247-yDKylLUSfSsoE4sGXy3a145CwDa8,31414
49
+ dissect/target/helpers/configutil.py,sha256=xXCmQA939iacd6cHr1SwNv6dyUo2bKMWsAI0TxwL24I,31428
50
50
  dissect/target/helpers/cyber.py,sha256=2kAA2YjWnPfKn_aTmRSse4uB64lq6AnNX19TD8Alylc,16830
51
51
  dissect/target/helpers/descriptor_extensions.py,sha256=uT8GwznfDAiIgMM7JKKOY0PXKMv2c0GCqJTCkWFgops,2605
52
52
  dissect/target/helpers/docs.py,sha256=G5Ll1cX2kYUfNcFFI-qjeUQ5Di60RAVpVnlB72F4Vqk,5153
@@ -60,12 +60,12 @@ dissect/target/helpers/mount.py,sha256=7Y4B0uY2c00p23hmuMKSgwAwxkKcY4spyAMO1kdcV
60
60
  dissect/target/helpers/mui.py,sha256=i-7XoHbu4WO2fYapK9yGAMW04rFlgRispknc1KQIS5Q,22258
61
61
  dissect/target/helpers/polypath.py,sha256=h8p7m_OCNiQljGwoZh5Aflr9H2ot6CZr6WKq1OSw58o,2175
62
62
  dissect/target/helpers/protobuf.py,sha256=b4DsnqrRLrefcDjx7rQno-_LBcwtJXxuKf5RdOegzfE,1537
63
- dissect/target/helpers/record.py,sha256=TxG1lwW5N0V-7kuq4s2vnQh-hAbT7rVwwZLf4sIDNjM,6334
63
+ dissect/target/helpers/record.py,sha256=VRwPE8OIotWzfxw-_ep_eXG-Iml6xzhodwPlbQYYaoY,6540
64
64
  dissect/target/helpers/record_modifier.py,sha256=cRNDhUYMmx4iEKyEr5Pqy9xiFgxr_GBNJPp_omkQsEU,4094
65
65
  dissect/target/helpers/regutil.py,sha256=hnJRTOQs4IqN4EroBoSNC4HDvuA8w6U1dqNBvu-ILn0,28376
66
66
  dissect/target/helpers/shell_application_ids.py,sha256=hYxrP-YtHK7ZM0ectJFHfoMB8QUXLbYNKmKXMWLZRlA,38132
67
67
  dissect/target/helpers/shell_folder_ids.py,sha256=Behhb8oh0kMxrEk6YYKYigCDZe8Hw5QS6iK_d2hTs2Y,24978
68
- dissect/target/helpers/utils.py,sha256=K3xVq9D0FwIhTBAuiWN8ph7Pq2GABgG3hOz-3AmKuEA,4244
68
+ dissect/target/helpers/utils.py,sha256=1UZNTUVBmtS2clbyIsi6mHOVw0jqPktM8OwCxCbOiY0,4587
69
69
  dissect/target/helpers/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  dissect/target/helpers/compat/path_310.py,sha256=PsLDIodlp3Hv5u-w7GDl6_LnTtchBYcRjz2MicX1egg,16982
71
71
  dissect/target/helpers/compat/path_311.py,sha256=2aydxCMWu1pN8PTBCo8HUbHRMC1xO-hj013j4QxaogE,18182
@@ -190,7 +190,7 @@ dissect/target/plugins/general/config.py,sha256=Mdy9uhWn4OJ96zfXpLgjVifV5SrViqHn
190
190
  dissect/target/plugins/general/default.py,sha256=8W_9JV3jKEeETlyTrB25sACoIIFmmO8wlVU5Zoi51W0,1425
191
191
  dissect/target/plugins/general/example.py,sha256=mYAbhtfQmUBj2L2C1DFt9bWpI7rQLJwCIYUsNLcA_pc,6053
192
192
  dissect/target/plugins/general/loaders.py,sha256=z_t55Q1XNjmTOxq0E4tCwpZ-utFyxiLKyAJIFgJMlJs,1508
193
- dissect/target/plugins/general/network.py,sha256=TWfSdI5fTgwe1_nV7u_ldtvvRwgmkVFLd4XFzy4cEZU,3257
193
+ dissect/target/plugins/general/network.py,sha256=I9wdFbBkDik1S9zvTi7sN20MdjJ2c_5tT8X8bgxWx5U,3257
194
194
  dissect/target/plugins/general/osinfo.py,sha256=oU-vmMiA-oaSEQWTSyn6-yQiH2sLQT6aTQHRd0677wo,1415
195
195
  dissect/target/plugins/general/plugins.py,sha256=9KJ70YvYwBfxt19C9yISv8YE4mOdHNvP16fTCTHC68U,6033
196
196
  dissect/target/plugins/general/scrape.py,sha256=Fz7BNXflvuxlnVulyyDhLpyU8D_hJdH6vWVtER9vjTg,6651
@@ -220,7 +220,7 @@ dissect/target/plugins/os/unix/bsd/openbsd/__init__.py,sha256=47DEQpj8HBSa-_TImW
220
220
  dissect/target/plugins/os/unix/bsd/openbsd/_os.py,sha256=9npz-osM-wHmjOACUqof5N5HJeps7J8KuyenUS5MZDs,923
221
221
  dissect/target/plugins/os/unix/bsd/osx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
222
222
  dissect/target/plugins/os/unix/bsd/osx/_os.py,sha256=hNFB1rwahLwgZD1kc3T4xalFusT88EoxM2Mh-8jOW_w,3440
223
- dissect/target/plugins/os/unix/bsd/osx/network.py,sha256=0Qf1jsCDNPmc_L-AmrvHjXaN_x-AtT1Ow3tdQOvFRsk,3734
223
+ dissect/target/plugins/os/unix/bsd/osx/network.py,sha256=3m71T-T-DnZFVidrokuHpr89lZOe_4drt-Xwam1ebfw,3767
224
224
  dissect/target/plugins/os/unix/bsd/osx/user.py,sha256=5rsGhsntBW9IXYIOrLpfYpSsJcBDL61QJkuZ456lXlE,2411
225
225
  dissect/target/plugins/os/unix/esxi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
226
226
  dissect/target/plugins/os/unix/esxi/_os.py,sha256=s6pAgUyfHh3QcY6sgvk5uVMmLvqK1tIHWR7MSbrFn8w,17789
@@ -233,6 +233,7 @@ dissect/target/plugins/os/unix/linux/environ.py,sha256=n7KttVzUtBHTIXQuS1DI5Azv6
233
233
  dissect/target/plugins/os/unix/linux/iptables.py,sha256=qTzY5PHHXA33WnPYb5NESgoSwI7ECZ8YPoEe_Fmln-8,6045
234
234
  dissect/target/plugins/os/unix/linux/modules.py,sha256=-LThb5mcKtngVfIICpdOGLtgJPc99WQ8Qufwddt8YgQ,2500
235
235
  dissect/target/plugins/os/unix/linux/netstat.py,sha256=EBpbK4BD3pZ0fKCR3ZMmVip4eQ0f6x_9yumA8vsUKPw,1691
236
+ dissect/target/plugins/os/unix/linux/network.py,sha256=KfGfYhtrzpHHefaHjTpdbGSLu6IN4anweYt3V02D9zU,14392
236
237
  dissect/target/plugins/os/unix/linux/network_managers.py,sha256=nr0gA3hBqsvP9k6xAYmRYwGRB1kMtXB1k0pe78jWdFI,25768
237
238
  dissect/target/plugins/os/unix/linux/proc.py,sha256=jm35fAasnNbObN2tpflwQuCfVYLDkTP2EDrzYG42ZSk,23354
238
239
  dissect/target/plugins/os/unix/linux/processes.py,sha256=xAJswf06HZsY8JhQ11xfJw1OLTZ1q9XZbu7_a7k2UpY,2019
@@ -251,7 +252,7 @@ dissect/target/plugins/os/unix/linux/debian/proxmox/vm.py,sha256=Z5IDA5Oot4P2hh6
251
252
  dissect/target/plugins/os/unix/linux/debian/vyos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
252
253
  dissect/target/plugins/os/unix/linux/debian/vyos/_os.py,sha256=TPjcfv1n68RCe3Er4aCVQwQDCZwJT-NLvje3kPjDfhk,1744
253
254
  dissect/target/plugins/os/unix/linux/fortios/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
254
- dissect/target/plugins/os/unix/linux/fortios/_keys.py,sha256=jDDHObfsUn9BGoIir9p4J_-rg9rI1rgoOfnL3R3lg4o,123358
255
+ dissect/target/plugins/os/unix/linux/fortios/_keys.py,sha256=PMOYIaA_Bn-WHXBKgl2xwwNFwMc0TxWBmLfxCSkSFVs,215099
255
256
  dissect/target/plugins/os/unix/linux/fortios/_os.py,sha256=7ZIwWFEfYwE924IvGfuinv1mEP6Uh28pl8VHSmsGKmM,20152
256
257
  dissect/target/plugins/os/unix/linux/fortios/generic.py,sha256=dc6YTDLV-VZq9k8IWmY_PE0sTGkkp3yamR-cYNUCtes,1265
257
258
  dissect/target/plugins/os/unix/linux/fortios/locale.py,sha256=Pe7Bdj8UemCiktLeQnQ50TpY_skARAzRJA0ewAB4710,5243
@@ -289,7 +290,7 @@ dissect/target/plugins/os/windows/generic.py,sha256=RJ1znzsIa4CFxmdMh91SjMY_pnjw
289
290
  dissect/target/plugins/os/windows/jumplist.py,sha256=3gZk6O1B3lKK2Jxe0B-HapOCEehk94CYNvCVDpQC9nQ,11773
290
291
  dissect/target/plugins/os/windows/lnk.py,sha256=KTqhw0JMW-KjAxe4xlRDNSRSx-th-_nPVgTGyBaKmW0,7891
291
292
  dissect/target/plugins/os/windows/locale.py,sha256=QiLWGgWrGBGHiXgep5iSOo6VNim4YC-xd4MdW0BUJPA,2486
292
- dissect/target/plugins/os/windows/network.py,sha256=ni-qK1PyA3UJD3lRJZGEBLAXcwDVKXPa3rIor9G5OSw,11283
293
+ dissect/target/plugins/os/windows/network.py,sha256=lziv_oqmRaVKLW-Ep8CZqfd160eVmL1RswTlPgoVapg,11336
293
294
  dissect/target/plugins/os/windows/notifications.py,sha256=xxfMEY_noDxMVqvT3QS1a3j-X3qAYikOtT6v2owxuCY,17480
294
295
  dissect/target/plugins/os/windows/prefetch.py,sha256=wbbYoy05gWbJfRsM2ci4wPG7kM58OocVwXD3hkQlbRw,10647
295
296
  dissect/target/plugins/os/windows/recyclebin.py,sha256=zx58hDCvcrD_eJl9nJmr_i80krSN03ya8nQzWFr2Tw0,4917
@@ -380,10 +381,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
380
381
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
381
382
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
382
383
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
383
- dissect.target-3.20.dev64.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
384
- dissect.target-3.20.dev64.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
385
- dissect.target-3.20.dev64.dist-info/METADATA,sha256=73hFY_beD-il2ONIHLcS3CgcD_tvmcJTEo-HasaQHLM,13303
386
- dissect.target-3.20.dev64.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
387
- dissect.target-3.20.dev64.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
388
- dissect.target-3.20.dev64.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
389
- dissect.target-3.20.dev64.dist-info/RECORD,,
384
+ dissect.target-3.21.dev2.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
385
+ dissect.target-3.21.dev2.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
386
+ dissect.target-3.21.dev2.dist-info/METADATA,sha256=CTHczoLyn0a2fvRz-vr8ZIwgmq45_UFoO7PLB2SQpqA,13302
387
+ dissect.target-3.21.dev2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
388
+ dissect.target-3.21.dev2.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
389
+ dissect.target-3.21.dev2.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
390
+ dissect.target-3.21.dev2.dist-info/RECORD,,