Commit Graph
12 Commits
Author SHA1 Message Date
Zoltan Papp ecfbd686b8 [client, android] Expose ssh functionality for Android (#7156)
Adds an SSHClient gomobile binding so the Android app can run an SSH session over the tunnel with a PTY, exposed through a listener interface for the in-app terminal.

Server type is auto-detected from the SSH banner, which selects the auth path: JWT device-code flow, NetBird key, or a regular server (NetBird key first, then password). Host keys are verified against the peer registry for NetBird servers and trust-on-first-use for regular ones.
2026-08-18 18:49:13 +02:00
evgeniyChepelevandZoltan Papp f2318a8fef [client] iOS - Remove duplicate Login RPCs from the iOS SDK (#6931)
## Describe your changes

Removes redundant `Login` RPCs from the iOS SDK bindings.

## Issue ticket number and link

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)
- [ ] This change does **not** modify the public API, gRPC protocols,
functionality behavior, CLI / service flags, or introduce a new feature
— **OR** I have discussed it with the NetBird team beforehand (link the
issue / Slack thread in the description). See
[CONTRIBUTING.md](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTING.md#discuss-changes-with-the-netbird-team-first).

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License
Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

### Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6931"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with [code]smith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787779607&installation_model_id=427504&pr_number=6931&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6931&signature=ce1631be2a5ffdba58c44b4669b0d480dc9f956102cf10a0c7b5845a800cdc68"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with [code]smith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added an interactive iOS login option that starts authentication
directly when needed.
* Improved login flow handling, including clearer error reporting and
successful-login notifications.
* Login configuration is now saved automatically after successful
authentication when applicable.

* **Bug Fixes**
  * Prevented duplicate login requests during iOS startup.
* Improved startup behavior and error propagation when the management
service is unavailable.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Removes redundant `Login` RPCs from the iOS SDK bindings. Both changed
files are behind
the `ios` build tag — Android, desktop and the shared core are not
affected.

### Problem

`auth.Auth.IsLoginRequired()` is not a cheap probe: it calls
`doMgmLogin()` and classifies
the resulting error, so every "is login required?" check costs a **full
`Login` RPC**. There
is no lighter way to ask. As a result the iOS client issued ~7 `Login`
requests before the
first `Sync`, where Android issues ~3, and the extra ones were
indistinguishable from real
logins in the management logs.

Three of those came from this package:

1. `Run()` called `LoginSync()` before starting the engine, which
performs `IsLoginRequired`
**and** `Login` — two RPCs. This duplicated the engine's own
`loginToManagement`
(`client/internal/connect.go`), which runs immediately before the first
`Sync` and is the
authoritative login. The `Login(ctx, "", "")` inside `LoginSync` could
not even establish
anything: with an empty setup key and empty JWT, a registration attempt
fails by
   construction, so it was a pure check.
2. `Auth.login()` called `IsLoginRequired()` again before opening the
browser, even when the
   caller had already determined that login is needed.

This is not only wasted traffic:

- **It pushes peers toward the server-side login ban.** In
`management/internals/shared/grpc/loginfilter.go`, every login with
unchanged metadata
increments `sessionCounter`, and exceeding `reconnLimitForBan` (30)
within
`reconnThreshold` (5 min) bans the peer for `baseBlockDuration` (10
min), doubling on
repeat. Redundant logins carry identical metadata, so they count against
exactly this
budget. At 7 logins per connect the budget is exhausted after ~4
reconnects instead of
  ~10 — reachable on flaky mobile networks.
- **Each redundant check is a potential 2-minute stall.**
`IsLoginRequired` retries with
backoff up to `MaxElapsedTime` (2 min) and returns `true` on failure, so
an unreachable
server was reported as "login required" rather than as a timeout, and
the `LoginSync`
  pre-flight could abort engine startup on that basis.

### Changes

**`client/ios/NetBirdSDK/client.go`** — `Run()` no longer performs the
`LoginSync()`
pre-flight. The engine's `loginToManagement` remains the single
authoritative login.

**`client/ios/NetBirdSDK/login.go`** — new exported `LoginInteractive`,
which skips the
`IsLoginRequired()` pre-flight and goes straight to the browser /
device-code flow, for
callers that have already established login is required.
`LoginWithDeviceName` keeps the
check for callers where the auth state is unknown (tvOS). Both now
delegate to a shared
`startLogin()`.

### Why this is safe

An expired or revoked session still fails the connection, one step later
and through a
single path: `loginToManagement` returns `PermissionDenied` → the
deferred
`MarkManagementDisconnected` records it on the shared status recorder →
`ClientStop` fires
the listener's disconnect callback, where `IsLoginRequiredCached()`
reports login-required →
the client tears the tunnel down. The error is also returned out of
`Run()`.

Where the server is unreachable, the engine now retries with backoff and
recovers on its
own instead of aborting the start.

Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com>
2026-08-02 09:51:14 +02:00
Zoltan Papp d15830a2d0 [client] Sync 0.74.6 fix/ios-relogin (#6795)
## sync 0.74.6 fix/ios-relogin

NewAuth built a fresh in-memory config on every call via
CreateInMemoryConfig, which generates a new WireGuard private key when
none is set. The iOS Swift layer calls this on interactive re-login and
writes the resulting config back to the profile's netbird.cfg, so each
re-auth replaced the peer's persisted private key with a new one. A new
key means a new public key, so the management server registered a
brand-new peer on every re-authentication — named after the fallback
hostname.

Load the existing config with DirectUpdateOrCreateConfig when a config
file is already present so re-login reuses the peer's persisted private
key (and its identity). Only fall back to a fresh in-memory config for
the first-time login when no config file exists yet (or after logout,
which deletes the file). DirectUpdateOrCreateConfig uses non-atomic
writes so it also works inside the tvOS App Group sandbox. This matches
what Run() and LoginForMobile() already do.

## Describe your changes

## Issue ticket number and link

## Stack

<!-- branch-stack -->

### Checklist
- [x] Is it a bug fix
- [ ] Is a typo/documentation fix
- [ ] Is a feature enhancement
- [ ] It is a refactor
- [ ] Created tests that fail without the change (if possible)
- [ ] This change does **not** modify the public API, gRPC protocols,
functionality behavior, CLI / service flags, or introduce a new feature
— **OR** I have discussed it with the NetBird team beforehand (link the
issue / Slack thread in the description). See

[CONTRIBUTING.md](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTING.md#discuss-changes-with-the-netbird-team-first).

> By submitting this pull request, you confirm that you have read and
agree to the terms of the [Contributor License

Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md).

## Documentation
Select exactly one:

- [ ] I added/updated documentation for this change
- [x] Documentation is **not needed** for this change (explain why)

### Docs PR URL (required if "docs added" is checked) Paste the PR link
from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/netbirdio/codesmith/netbird/pr/6795"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img
alt="View with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a>
<a
href="https://backend.blacksmith.sh/track/enable-autofix?expires=1786784867&installation_id=146802194&pr_number=6795&repository=netbirdio%2Fnetbird&return_to=https%3A%2F%2Fgithub.com%2Fnetbirdio%2Fnetbird%2Fpull%2F6795&signature=01bd94ea58128257c33f4d430ab3b71ce21eac02577ce90c009105b8c0027d9c"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img
alt="Autofix with Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a>
<sup>Need help on this PR? Tag <code>/codesmith</code> with what you
need. Autofix is disabled.</sup>

<!-- codesmith:autofix:disabled -->
<!-- /codesmith:footer -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved iOS login handling when a configuration location is provided.
- Existing WireGuard keys can now be reused across subsequent logins,
helping avoid unnecessary key regeneration.
- Login continues to support temporary in-memory configuration when no
persistent location is available.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 14:38:01 +02:00
Zoltan Papp f736ef9647 [client/ios] Add Auth.Stop() to cancel an in-progress interactive login (#6486)
The iOS PKCE login runs in the main-app process, decoupled from the network
extension (the extension's client context is torn down on login-required, which
would otherwise kill the WaitToken goroutine before the OAuth callback arrives).
Because it is decoupled, nothing aborted the flow when the user dismissed the
browser without logging in: WaitToken kept its loopback HTTP server bound to the
redirect port until the flow expired, so the next connect stalled trying to bind
the same port.

Make the Auth context cancellable and add Auth.Stop(), which cancels it. Cancelling
unblocks WaitToken, whose deferred server.Shutdown frees the port immediately. This
mirrors how Android's stopEngine() aborts login via the engine context.

NewAuthWithConfig now also derives a cancellable context; its only iOS caller uses
LoginSync (no interactive server), so behaviour is unchanged there.
2026-06-22 13:27:21 +02:00
Zoltan Papp ded04b7627 [client] Consolidate authentication logic (#5010)
* Consolidate authentication logic

- Moving auth functions from client/internal to client/internal/auth package
- Creating unified auth.Auth client with NewAuth() constructor
- Replacing direct auth function calls with auth client methods
- Refactoring device flow and PKCE flow implementations
- Updating iOS/Android/server code to use new auth client API

* Refactor PKCE auth and login methods

- Remove unnecessary internal package reference in PKCE flow test
- Adjust context assignment placement in iOS and Android login methods
2026-01-23 22:28:32 +01:00
shuuri-labs 96cdd56902 Feat/add support for forcing device auth flow on ios (#4944)
* updates to client file writing

* numerous

* minor

* - Align OnLoginSuccess behavior with Android (only call on nil error)
- Remove verbose debug logging from WaitToken in device_flow.go
- Improve TUN FD=0 fallback comments and warning messages
- Document why config save after login differs from Android

* Add nolint directive for staticcheck SA1029 in login.go

* Fix CodeRabbit review issues for iOS/tvOS SDK

- Remove goroutine from OnLoginSuccess callback, invoke synchronously
- Stop treating PermissionDenied as success, propagate as permanent error
- Replace context.TODO() with bounded timeout context (30s) in RequestAuthInfo
- Handle DirectUpdateOrCreateConfig errors in IsLoginRequired and LoginForMobile
- Add permission enforcement to DirectUpdateOrCreateConfig for existing configs
- Fix variable shadowing in device_ios.go where err was masked by := in else block

* Address additional CodeRabbit review issues for iOS/tvOS SDK

- Make tunFd == 0 a hard error with exported ErrInvalidTunnelFD (remove dead fallback code)
- Apply defaults in ConfigFromJSON to prevent partially-initialized configs
- Add nil guards for listener/urlOpener interfaces in public SDK entry points
- Reorder config save before OnLoginSuccess to prevent teardown race
- Add explanatory comment for urlOpener.Open goroutine

* Make urlOpener.Open() synchronous in device auth flow
2025-12-30 16:41:36 +00:00
Diego Romar 08f31fbcb3 [iOS] Add force relay connection on iOS (#4928)
* [ios] Add a bogus test to check iOS behavior when setting environment variables

* [ios] Revert "Add a bogus test to check iOS behavior when setting environment variables"

This reverts commit 90ca01105a6b0f4471aac07a63fc95e5d4eaef9b.

* [ios] Add EnvList struct to export and import environment variables

* [ios] Add envList parameter to the iOS Client Run method

* [ios] Add some debug logging to exportEnvVarList

* Add "//go:build ios" to client/ios/NetBirdSDK files
2025-12-12 14:29:58 -03:00
hakansa cb8b6ca59b [client] Feat: Support Multiple Profiles (#3980)
[client] Feat: Support Multiple Profiles (#3980)
2025-07-25 16:54:46 +03:00
Viktor Liu bc7b2c6ba3 [client] Report client system flags to management server on login (#3187) 2025-01-16 13:58:00 +01:00
Foosecandbcmmbaga 4bbedb5193 [client] Add mTLS support for SSO login (#2188)
* Add mTLS support for SSO login
* Refactor variable to follow Go naming conventions

---------

Co-authored-by: bcmmbaga <bethuelmbaga12@gmail.com>
2024-08-13 18:07:44 +03:00
pascal-fischer 72a1e97304 add unimplemented as a valid error in SSO check (#1440) 2024-01-10 08:54:05 +01:00
pascal-fischerandMaycon Santos 818c6b885f Feature/add iOS support (#1244)
* starting engine by passing file descriptor on engine start

* inject logger that does not compile

* logger and first client

* first working connection

* support for routes and working connection

* small refactor for better code quality in swift

* trying to add DNS

* fix

* updated

* fix route deletion

* trying to bind the DNS resolver dialer to an interface

* use dns.Client.Exchange

* fix metadata send on startup

* switching between client to query upstream

* fix panic on no dns response

* fix after merge changes

* add engine ready listener

* replace engine listener with connection listener

* disable relay connection for iOS until proxy is refactored into bind

* Extract private upstream for iOS and fix function headers for other OS

* Update mock Server

* Fix dns server and upstream tests

* Fix engine null pointer with mobile dependencies for other OS

* Revert back to disabling upstream on no response

* Fix some of the remarks from the linter

* Fix linter

* re-arrange duration calculation

* revert exported HostDNSConfig

* remove unused engine listener

* remove development logs

* refactor dns code and interface name propagation

* clean dns server test

* disable upstream deactivation for iOS

* remove files after merge

* fix dns server darwin

* fix server mock

* fix build flags

* move service listen back to initialize

* add wgInterface to hostManager initialization on android

* fix typo and remove unused function

* extract upstream exchange for ios and rest

* remove todo

* separate upstream logic to ios file

* Fix upstream test

* use interface and embedded struct for upstream

* set properly upstream client

* remove placeholder

* remove ios specific attributes

* fix upstream test

* merge ipc parser and wg configurer for mobile

* fix build annotation

* use json for DNS settings handover through gomobile

* add logs for DNS json string

* bring back check on ios for private upstream

* remove wrong (and unused) line

* fix wrongly updated comments on DNSSetting export

---------

Co-authored-by: Maycon Santos <mlsmaycon@gmail.com>
2023-12-18 11:46:58 +01:00