Skip to content

fix: detect lr parameter with value as loose routing in ACK#105

Merged
yeoleobun merged 1 commit intorestsend:mainfrom
bevenky:fix/lr-param-with-value
Mar 23, 2026
Merged

fix: detect lr parameter with value as loose routing in ACK#105
yeoleobun merged 1 commit intorestsend:mainfrom
bevenky:fix/lr-param-with-value

Conversation

@bevenky
Copy link
Contributor

@bevenky bevenky commented Mar 22, 2026

Problem

Some SIP proxies (e.g., Kamailio) send Record-Route with ;lr=on instead of bare ;lr:

Record-Route: <sip:proxy.example.com;lr=on;ftag=abc;did=xyz>

The rsip crate parses ;lr=on as Param::Other("lr", Some("on")) since Param::Lr only matches the valueless form (;lr with no =value).

This causes make_ack to fall into the strict routing branch instead of loose routing:

  • The ACK Request-URI is set to the Record-Route URI
  • The Contact (often an internal IP like 10.x.x.x) is placed in the Route header
  • destination_from_request picks the Route header as the UDP destination
  • The ACK is sent to the unreachable internal IP instead of through the proxy
  • The remote side never receives the ACK → "ACK Timeout" after ~30 seconds → call killed

This is similar to the issue fixed in PR #100 (incorrect Request-URI for ACK), but for the lr parameter detection specifically.

Fix

Check for both Param::Lr and Param::Other where the name is "lr" (case-insensitive):

.any(|param| matches!(param, rsip::Param::Lr) 
    || matches!(param, rsip::Param::Other(name, _) if name.to_string().eq_ignore_ascii_case("lr")))

This matches ;lr, ;lr=on, ;lr=true, etc. as loose routing per RFC 3261 Section 16.6.

Testing

Tested with a SIP proxy that sends Record-Route: <sip:proxy.example.com;lr=on;...>:

  • Before fix: ACK sent to internal Contact IP (e.g. 10.x.x.x:5060), call dies after 30s
  • After fix: ACK routed through Record-Route proxy, call stays alive

Note

The root cause is in the rsip crate's Param parser which only matches bare ;lr as Param::Lr (line 119 in rsip/src/common/uri/param/mod.rs). A fix there would also resolve this, but the workaround in make_ack is simpler and handles any lr variant.

Some SIP proxies (e.g., Kamailio) send Record-Route with ;lr=on
instead of bare ;lr. The rsip crate parses ;lr=on as
Param::Other("lr", Some("on")) since Param::Lr only matches the
valueless form (;lr with no =value).

This causes make_ack to fall into the strict routing branch,
putting the Record-Route URI as the Request-URI and the Contact
as the Route header. The ACK is then sent to the Contact address
(often an unreachable internal IP behind a load balancer) instead
of through the Record-Route proxy. The remote side never receives
the ACK and terminates the call with "ACK Timeout".

The fix checks for both Param::Lr and Param::Other where the
name is "lr" (case-insensitive), matching ;lr, ;lr=on, ;lr=true,
etc. as loose routing per RFC 3261 Section 16.6.
@bevenky bevenky force-pushed the fix/lr-param-with-value branch from cd49cf6 to 2826f12 Compare March 22, 2026 21:12
@yeoleobun
Copy link
Collaborator

Thanks

@yeoleobun yeoleobun merged commit 3c46258 into restsend:main Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants