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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,