Skip to content

[BUG] mid_registrar: self-generated (de)REGISTER egresses the wrong socket on multi-socket / anycast nodes #3953

Description

@denyspozniak

OpenSIPS version

3.6.7 (x86_64/linux) — the relevant code path is also present on master.

Environment

A proxy with two listening sockets — an external one (client-facing) and an internal one (towards the main registrar) — running mid_registrar (reproduced in mode=2, AOR throttling, but the relevant code path is
mode-independent).

Description

When mid_registrar generates its own REGISTER / de-REGISTER toward the main registrar (e.g. on contact trim, expiry, or refresh), the request leaves via the external socket instead of the internal one used by the normally
proxied REGISTER. The client-initiated REGISTER is relayed correctly (the script controls the socket), but the module-generated transaction is not subject to that logic and ends up with the wrong source / Via. On an anycast node
this is harmful: the source / Via is the shared anycast address, so the registrar's response can be delivered to a different cluster member and the transaction never completes.

Root cause

The self-generated request is built in ulcb.c with a NULL send socket:

/* ulcb.c: send_unregister() */
if (tmb.new_auto_dlg_uac(from, to, ruri, callid, NULL, &dlg)) {   // socket arg is NULL

https://github.com/OpenSIPS/opensips/blob/master/modules/mid_registrar/ulcb.c#L82

unregister_contact() reads back every ucontact key it needs (from / to / main_reg_uri / next-hop / callid / cseq) but never a socket, so nothing is passed down:

https://github.com/OpenSIPS/opensips/blob/master/modules/mid_registrar/ulcb.c#L115-L167

With dst.send_sock unset, the core's get_send_socket() falls back to the inbound bind_address (= the external / anycast socket), orfor timer-driven expire/refresh, where there is no inbound messageto the protocol default
socket:

https://github.com/OpenSIPS/opensips/blob/master/forward.c#L177-L189

For contrast, the save path already selects a meaningful socket (c->sock ? c->sock : bind_address); only the regeneration path drops it:

https://github.com/OpenSIPS/opensips/blob/master/modules/mid_registrar/save.c#L787

Expected

The module-generated (de)REGISTER should egress the socket appropriate for reaching the main registrarideally the same socket used when the corresponding upstream registration was sentindependent of which socket the client
REGISTER arrived on, and without relying on bind_address.

Proposed fix (any of)

1. Persist the send socket used for the upstream registration alongside the other stored ucontact keys and pass it to new_auto_dlg_uac() instead of NULL.
2. Add a mid_registrar modparam to bind the outgoing socket (analogous to uac_registrant's forced_socket_column).
3. As a minimum, honor force_send_socket() set from local_route for these locally-generated requests.

Workaround

Detect the locally-generated REGISTER in local_route and call force_send_socket().

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions