Commit graph imsd/interfaces/Imsd-Ipsec.cppm
Author SHA1 Message Date
799fd1a802
engine, messages, util, imsd: the reregistration carries the last challenge answer and new SA parameters
The keepalive refresh and the resume's re-REGISTER carried an initial
registration's first-REGISTER Authorization — an empty nonce and
response — in the second REGISTER's frame, with a Security-Client
naming the SPIs and ports in use. TS 24.229 5.1.1.4.2 has a
reregistration carry the Authorization
of the last successful authentication — the last received nonce and
the last calculated response — and a Security-Client with the new
parameter values for the two SA pairs a re-authentication would set
up; TS 33.203 7.4.0 keeps the server ports and changes the client
ports. O2 UK refused the refresh of the old shape with 503 on every
occasion on record (alyx, 2026-09-24 to 10-08, a stationary phone
included) and accepted the fresh registrations that followed; KPN
accepted the old shape without a challenge.

The fresh registration now records the 401's nonce, our cnonce and
the response in the registration state (auth_nonce, auth_cnonce,
auth_response in the state file); a reregistration sends them
verbatim, mints new SPIs and proposes PortUcNext (45063) as the
client port with the server port unchanged. A registration resumed from a
state file written before this change has no answer: its
reregistrations carry the empty digest, as before, until its next
fresh registration, and the resume says so. A 401 to a reregistration asks
for re-authentication over temporary SAs on the proposed ports (TS
24.229 5.1.1.5.1), which imsd does not implement: the refresh throws
it as a refusal and RegRecovery makes the next step the fresh
registration, replacing the in-place answer over the old SAs.

Tested with the Messages and Engine suites and on the dev phone (KPN)
with a build of this commit's tree: a resume from the previous state
file, a fresh registration, a resume that sent the stored answer,
three refreshes at a 120-s interval, an outgoing call to a bench line
and an incoming call's ring.
2026-10-10 21:43:07 +02:00
7eb2deae0c
ims-pdn-up, imsd: register on the PDN's own address, not the kernel's temporary one
imsd took the first global IPv6 on the ims netdev as its address, and
the kernel lists the temporary (privacy) SLAAC address first: `temporary
dynamic`, preferred for a day and valid for two by its lifetimes (read
2026-09-24). Contact, Via and the four SAs were bound to it, so once the
kernel removes it the registration has lost its address. The address
ModemManager assigned — the one the script installs — sat third on the
list. Seen on the dev phone; a field unit's journal shows the split too
— imsd registered on an address other than the one the script installed
(ims ledger F18).

Hand the assigned address to the daemon as LOCAL through /run/imsd.env,
next to DEV. For a manual run without it, prefer a global address that
is neither `temporary` nor `dynamic`, then any non-temporary one.

A restart after the upgrade finds the registration's SAs on the old
address. It resumes there while that address is still on the link, and
moves to the PDN's address in place: with its next fresh registration,
or when the old address leaves the link first. When the address it is
registered on leaves the netdev and the PDN's own address is not there
to move to, a registered imsd exits at its next recovery step, non-zero,
for a systemd restart, which runs the PDN bring-up again.

Tested on the dev phone (KPN) in builds of this series; not every path
has run there.
2026-10-06 14:01:33 +02:00
52736295a1
ipsec: build the SAs from the Security-Server mechanism the UE selects
A P-CSCF may answer the challenge with every mechanism it supports and
attach the SPIs and ports to the one it applied. O2 UK's core lists six
ipsec-3gpp entries with q-values, md5 first, and marks the fourth (sha1,
no ealg). imsd took the first ealg= anywhere in the header - the 3DES of
an entry the P-CSCF had not selected - and installed SAs the far end
could not decrypt: every protected packet after the 401 was dropped at
its IPsec layer, over TCP and UDP alike, with nothing to answer.

The 401 handling now parses the Security-Server as a mechanism list
(commas outside quotes, parameters on semicolons, names and values
case-insensitive) and selects the highest-q ipsec-3gpp mechanism that
matches what Security-Client offered (RFC 3329 2.3.1, TS 24.229
5.1.1.5.1): alg equal to ours, ealg (absent = null) equal to the offer.
The SPIs and ports are per registration and come from the entry carrying
them. When no entry matches the offer, the entry carrying the SPIs is
installed as listed and the journal says so; hmac-md5-96 becomes
hmac(md5) with IK as the key. A single-mechanism header selects itself:
on KPN the SAs are the same as before (unit-pinned argv, verified on the
phone). An answer that cannot be used - no ipsec-3gpp entry, a missing
spi/port, an alg, ealg, prot or mod the kernel cannot be handed - defers
the bring-up on the throttle schedule with the reason, before the AKA is
spent, instead of a fatal that would restart imsd every RestartSec with
an initial REGISTER each time; spi-s=0 stays the throttle deferral.
Repeated Security-Server header lines are joined into the one list
Security-Verify echoes.

The journal shows the Security-Server line, the selected mechanism, the
SA parameters, and any ip xfrm command that fails (keys masked) at every
fresh registration - the silence this bug produced had no line to read.
2026-09-19 21:36:57 +02:00
6e77823933 imsd 0.2.7 — initial public snapshot
Userspace VoLTE/IMS daemon for mainline Linux phones (developed on the
Fairphone 6): a GLib-free core (SIP, SDP, USIM AKA, IPsec SA setup, RTP
media, call engine) behind a GDBus control daemon, a standalone AMR-WB
media leg, and a Plasma Dialer backend. C++26 modules built with Crafter
Build; the tree is clean under the project's house-style linter
(crafter-build lint) across all three build products.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
2026-07-22 23:04:21 +02:00