Repository navigation
v0.22.13
What's Changed
Added
- The RDP connection editor gains a KDC Address row for Kerberos sign-in, and an empty row now falls back to the realm's own DNS name (issue #351) — on a machine joined with realmd/sssd,
/etc/krb5.confusually has nokdc =line and the embedded client's Kerberos library does not look up DNS SRV records on Linux, so Kerberos sign-in failed with "No KDC server found" and there was no way to name a KDC. A KDC Address row under the Kerberos Authentication switch, sensitive only while the switch is on, takes a domain controller name or address (dc1.example.com,dc1.example.com:88,[2001:db8::1]:88, normalized totcp://…:88), atcp://orudp://address, or anhttps://MS-KKDCP KDC proxy URL. It is stored in the existingkdc_proxy_urlfield, so the file format does not change, and an invalid value is now a validation error in the editor instead of being logged and dropped at connect time. With the row empty, the KDC still comes first fromSSPI_KDC_URL_<REALM>/SSPI_KDC_URLand from the realm's[realms]entry inkrb5.conf, and only when neither names one does RustConn fall back totcp://<realm in lowercase>:88, which in Active Directory resolves to the domain controllers. Before connecting with Kerberos on, RustConn now also warns when Host is an IP address or a tunnel endpoint (the service principal isTERMSRV/<host>) and when Domain is a short NetBIOS name rather than the DNS domain.
Fixed
- Group Sync no longer loses a connection's monitoring override on a Master/Import sync (issue #352) — the
.rcnGroup Sync format carried every synced field of a connection except its per-connection monitoring override, so a connection set to Enabled, Disabled or to its own polling interval came through the sync following the global switch again, and an interval-only override (one that follows the global switch but pins its own interval) was dropped the same way. The override now travels in the.rcnfile in a new optionalmonitoring_configfield and is re-applied when the Import side creates or updates the connection. A connection with no override (the common case) still writes nothing, so a 0.22.12 reader is unaffected and files stay readable in both directions. Duplicate and paste already preserved the override. (Note: the native single-connection export/import and local duplicate/paste were never affected; only the Master/Import Group Sync path dropped it.) - A connection's monitoring setting can follow the global switch again, and connections saved before are one action away from doing so (issue #352) — the connection editor's Enable Monitoring row was an on/off switch built switched on, a connection without its own value was shown as on, and saving always stored an explicit on or off. Every connection saved in the editor therefore pinned itself on and kept monitoring after the global switch in Settings was turned off, and each save also dropped a polling interval set with
rustconn-cli monitor enable --interval. The row is now a choice of Use global setting (the default for new connections), Enabled (runs even with the global switch off, as before) and Disabled (never runs and opens no monitoring SSH session, as before). A connection without its own value shows as Use global setting, and saving changes only the on/off value, so a per-connection interval survives. Files from 0.22.12 load unchanged, and no migration runs, because an old explicit on cannot be told apart from a deliberate one. Instead, Settings → Monitoring → Reset Per-Connection Overrides shows how many connections set their own value and, once confirmed, makes them all follow the global switch, keeping their intervals;rustconn-cli monitor reset <name>andmonitor reset --alldo the same from the command line.rustconn-cli monitor metricsalso reported a connection without its own value as disabled whatever the global switch said; it now resolves it the way an SSH session does, and its JSON and CSV output gainoverrideandeffective_interval_secsfields, appended at the end of the CSV row. - RDP sign-in failures now say what went wrong instead of "Check username and password" (issue #351) — every CredSSP error the embedded client did not recognise, including Kerberos's "no KDC found", became "NLA authentication failed. Check username and password.", and an account-restriction refusal gave no hint that Kerberos is the way in. The failure is now classified in
rustconn_core::rdp_client::failureand shown as a translated message for each case: no KDC for the realm, KDC unreachable, a clock more than five minutes off, a server unknown to the domain under the name in Host, invalid credentials, and a disabled, locked, expired or restricted account. An account restriction with Kerberos off now tells the user to turn on Kerberos Authentication, which is what a member of the Protected Users group needs.0xc0000070(STATUS_INVALID_WORKSTATION) was reported as "password must be changed"; it is now a logon restriction. - A corrected vault entry is used on the next attempt after a refused sign-in, instead of only after a restart (issue #351) — after a successful lookup RustConn keeps a connection's credentials in memory for five minutes so quick reconnects do not hit the vault again, and nothing dropped them when the sign-in they were used for failed. A user who fixed a wrong username or password in the vault and retried within those five minutes was refused again with the same credentials, so only restarting seemed to help; with Bitwarden the
bwclient could also go on answering from its local copy of the vault for up to two minutes after the last check. Now, when an RDP or VNC connection fails before its session starts, or an SSH session exits with ssh's authentication-failure status (255), RustConn drops the cached credentials for that connection and makes the next Bitwarden lookup runbw syncfirst, so the retry reads the vault again. A session that connected and dropped later keeps its credentials. Credentials cached for an SSH jump host are not dropped this way yet, because ssh's exit status does not say which hop refused the password. - FreeRDP 2 is no longer launched, and an embedded FreeRDP session that ends at once is no longer shown as connected (issue #351) — Debian and Ubuntu ship FreeRDP 2 as
wlfreerdpandxfreerdp, but RustConn hands every FreeRDP client its arguments through/args-from:and uses other options only FreeRDP 3 has, so FreeRDP 2 printed its usage text and quit. The embedded mode hard-codedwlfreerdp, sent its stderr to/dev/nulland counted a successful spawn as a connection, so the tab showed "Connected" over a client that had already exited; it also removed the temporary arguments file as soon as the process was spawned, racing the client that still had to read it. Each client is now asked for its version once, the answer is cached, and FreeRDP older than 3 is skipped for embedded, external and RemoteApp launches alike. Embedded mode preferswlfreerdp3, and when only FreeRDP 2 is installed a toast names the refused version and asks for FreeRDP 3. The embedded client's stderr is kept in a bounded buffer: an exit right after launch is reported as a failed connection, classified from that output the way the external client's early exit already was, and a later exit as the session ending. The arguments file now outlives the client's start-up. The reason a connection has to use FreeRDP instead of the built-in client (TLS without NLA, legacy RDP security or TLS level, RemoteApp, remote audio) is now a translated sentence instead of a debug dump, and a RemoteApp launch with Kerberos Authentication on no longer forces NTLM with/auth-pkg-list:ntlm, which a Protected Users account can never pass. - Terminal highlight rules now stay on their text after scrolling, resizing or moving the window (issue #343) — the highlight layer took the top visible row as the whole-number part of the terminal's scroll position and drew every row from there. Touchpad scrolling and scrollbar drags leave that position between two rows, so every highlight sat part of a row too low, and the partly visible row at the top was never drawn. The layer also repainted only when the terminal's text, cursor or font changed, so after a resize, a maximise change or a move to a display with a different scale the highlights stayed where they had been. A new pure
viewport_rows()inrustconn_core::highlightnow returns the first visible buffer row together with its sub-row pixel offset, the layer draws at that offset with one extra row and clips to the terminal grid, and it repaints on the scroll adjustment'svalue-changedandchangedsignals and on a scale-factor change, disconnecting those handlers when the layer is dropped. Covered by unit and property tests forviewport_rows()and an opt-in VTE contract test. Colouring the matched text itself, rather than drawing over it, is planned for 0.23. - A config file RustConn cannot read is no longer silently replaced with defaults, and a file written by a newer RustConn is backed up before an older one changes it — when
config.toml, or the clusters, connection history, Simple Sync tombstones or custom terminal themes file, did not parse (typically because a newer RustConn wrote a value this version does not know, or after a bad hand edit), startup fell back to defaults, and the next routine save (a KeePass check, a search, expanding a group) overwrote the file with them, so the settings were lost for good. Startup now copies such a file byte for byte, owner-only, to<file>.unreadable-<UTC timestamp>before falling back, logs it, and shows a banner naming the copy. Every save ofconfig.toml,connections.tomlandgroups.tomlnow records the version that wrote it in a newwritten_bykey. When a file comes from a newer release, the first save from this version copies it to<file>.<version>.bakbeforehand, a failed copy aborts that save instead of overwriting the newer file, and the main window shows a banner. Releases without the marker ignore the new key, so the files stay readable in both directions. A connections or groups file that does not parse still stops startup with an error, as before. - Group Sync no longer trashes and recreates every connection when the Import group's name differs from the Master's — both sides matched connections and subgroups by a path that began with the synced root group's own name, and the Settings "Import" button names the local root after the file rather than after the Master's group. With a Master root called anything but the file name, nothing ever matched, so every sync moved all connections to Trash and created them again with new IDs, losing history, pins, cluster and workspace membership and the route-change warning, and filling the Trash with duplicates. Matching now uses the path inside the synced group, so renaming or moving the local Import group no longer changes what matches. Emptying the Trash, or the Undo window closing, also no longer deletes a vault password that a live connection still resolves to: a vault key is built from name, group path and protocol, so the trashed copy and its live twin shared one entry, and the purge removed it for both. Startup sync now applies each result to its group by ID instead of by name, which picked the first of two same-named groups. Group Sync exports now carry connection and group IDs in an optional
idfield for a later ID-based match; the format version stays 1, and older RustConn versions read these files unchanged. Still open, and documented in the User Guide: a rename or move on the Master is seen as a removal plus an addition, and a connection or subgroup that a sync adds inside a subgroup is created directly in the synced group, so it is recreated on the next sync. - Saving a KeePass credential with a hardware key now asks for far fewer touches, serializes concurrent writes, and shows what the blinking key is waiting for (issue #350) — a single save walked the KeePass database with
keepassxc-cliseveral times over (list the RustConn group, list andmkdireach parent level, delete any existing entry, thenadd), and a rename read the password, username and URL back out before rewriting them. Each of those steps re-opens the database, and with a YubiKey in Challenge-Response mode every open blocks on a physical touch, so one save could demand five touches and one rename eleven. Worse, KeePassXC re-derives the KDBX 4 key on every save, so even a minimal write is challenged twice. Writes now go through one internal runner: a save probes the tree once,mkdirs only the levels that are missing, andedits the entry in place (oradds it when absent) with no delete; a rename or move usesmvandedit -tand never reads the password back. This path is used only with keepassxc-cli 2.5.0 or newer (which the probe/edit flags need); older versions keep the previous algorithm. All KeePass writes — save, rename and delete — are now serialized by a process-wide lock, so a save triggered while the credentials editor is open can no longer interleave with another write and corrupt the entry. And because RustConn runs the CLI quietly and reads its output only after it exits, KeePassXC's own "touch your YubiKey" prompt never reached the user; the GUI now shows a banner, andrustconn-cli secretprints a line on stderr, for as long as a run is waiting on the key. The database password is never passed on the command line, so it cannot appear in a process listing or a log.
Changed
- Debian and OBS packages no longer recommend FreeRDP 2 (issue #351) —
Recommends:offeredfreerdp2-x11first indebian/control, the OBS Debian control file and the release workflow's.debmetadata, which steered Ubuntu 24.04 users to a FreeRDP that RustConn cannot drive. The alternatives are nowfreerdp3-x11 | freerdp3-wayland, andINSTALL.md, the User Guide andWSL.mdstate that the external client needs FreeRDP 3.
Documentation
- Remote monitoring is documented as SSH-only and metrics-only — the User Guide said monitoring works with Telnet and Kubernetes sessions too, but it starts only from SSH sessions. It now says so, and that the bar shows metrics without thresholds, alerts or actions. The CLI reference documents
monitor resetand the fieldsmonitor metricsprints. - Corrected the 0.22.12 description of Kerberos for RDP (issue #351) — the 0.22.12 entry said the embedded client signs in with a ticket from
kinit, finds the KDC through DNS/SRV and falls back to NTLM where Kerberos is not possible. None of the three holds: the client requests its own tickets with the password saved for the connection and never reads the ticket cache, it finds the KDC through the KDC Address row,SSPI_KDC_URL_<REALM>/SSPI_KDC_URL,krb5.confor the realm-name fallback (DNS SRV records are not looked up on Linux), and a KDC that cannot be found or reached ends the sign-in instead of switching to NTLM. The code comments now say so, and the User Guide has a new "Kerberos Authentication (Protected Users)" section covering what Kerberos needs: the saved password, the server's DNS name as Host, the DNS domain, and a clock within five minutes of the domain's.
Dependencies
- Updated five transitive crates to their latest semver-compatible patch/minor releases (
cargo update, advisories clean) —picky-asn1-der0.5.6→0.5.7 andpicky-asn1-x5090.15.4→0.15.5 (the ASN.1 crates IronRDP's CredSSP stack uses, refreshed alongside this release's Kerberos work), pluscfg-expr0.20.9→0.20.10,lazy_static1.5.0→1.5.1 andpin-utils0.1.0→0.1.1.picky-krbis held at 0.12.4: 0.12.5 adds aGssApiMessageErrorvariant that the pinnedsspi0.21.3 (an IronRDP dependency) does not match exhaustively, so it fails to compile until IronRDP'ssspiis bumped.
Installation
Flatpak (Recommended)
flatpak install flathub io.github.totoshko88.RustConnSnap
sudo snap install rustconnDebian/Ubuntu (.deb from this release)
sudo dpkg -i rustconn_0.22.13_amd64.deb
sudo apt-get install -f # Install dependencies if neededFedora (.rpm from this release)
sudo dnf install rustconn-0.22.13-1.fc44.x86_64.rpmAppImage
chmod +x RustConn-0.22.13-x86_64.AppImage
./RustConn-0.22.13-x86_64.AppImagemacOS (Homebrew)
brew tap totoshko88/rustconn
brew install rustconn
open $(brew --prefix)/opt/rustconn/RustConn.appAll dependencies (GTK4, libadwaita, VTE, Adwaita icons) are installed automatically.
Requires macOS 13 (Ventura) or later.
OBS Repositories
Packages available at: https://build.opensuse.org/package/show/home:totoshko88:rustconn/rustconn
# Debian 13 (Trixie)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Debian_13/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 24.04 LTS (Noble)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_24.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Ubuntu 26.04 LTS (Resolute)
echo 'deb http://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/ /' \
| sudo tee /etc/apt/sources.list.d/rustconn.list
curl -fsSL https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/xUbuntu_26.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/rustconn.gpg > /dev/null
sudo apt update && sudo apt install rustconn
# Fedora 44
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_44/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# Fedora 43
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/Fedora_43/home:totoshko88:rustconn.repo
sudo dnf install rustconn
# openSUSE Tumbleweed
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Tumbleweed/ rustconn
sudo zypper ref && sudo zypper in rustconn
# openSUSE Leap 16.0
sudo zypper ar https://download.opensuse.org/repositories/home:/totoshko88:/rustconn/openSUSE_Leap_16.0/ rustconn
sudo zypper ref && sudo zypper in rustconnArch Linux (AUR)
yay -S rustconnFreeBSD (Ports)
pkg install rustconnFull installation guide: https://github.com/totoshko88/RustConn/blob/main/docs/INSTALL.md