Skip to content

mod_sofia gateway unregister does not retry REGISTER Expires: 0 after 407 challenge with fresh nonce #319

@ankit-sapkota

Description

@ankit-sapkota

Version: v1.13.17

Summary

When unregistering a SIP gateway with:

sofia profile <profile> unregister <gateway>

FreeSWITCH sends a REGISTER with Expires: 0, receives 407 Proxy Authentication Required with a fresh nonce, but does not send a second authenticated REGISTER Expires: 0.

As a result, the remote registrar keeps the registration active until the registration TTL expires.

This was observed with a SIP registrar that challenges unregister requests with 407 Proxy Authentication Required.

Environment

FreeSWITCH version: 1.10.12-release+git~20240802T210227Z~a88d069d6f~64bit
Module: mod_sofia
Registrar/PBX: 3CX-compatible registrar
Transport: UDP
Profile: external
Gateway: gw_test

Gateway behavior

The gateway is registered successfully. On unregister, FreeSWITCH sends:

REGISTER sip:REDACTED_REGISTRAR_IP:5060;transport=udp SIP/2.0
Via: SIP/2.0/UDP REDACTED_FREESWITCH_IP:5080;rport;branch=z9hG4bK_REDACTED
Max-Forwards: 70
From: <sip:REDACTED_EXTENSION@REDACTED_REGISTRAR_IP>;tag=REDACTED_TAG
To: <sip:REDACTED_EXTENSION@REDACTED_REGISTRAR_IP>
Call-ID: REDACTED_CALL_ID
CSeq: REDACTED_CSEQ REGISTER
Contact: <sip:gw+gw_test@REDACTED_FREESWITCH_IP:5080;transport=udp;gw=gw_test>
Expires: 0
User-Agent: FreeSWITCH-mod_sofia/1.10.12-release+git~20240802T210227Z~a88d069d6f~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Proxy-Authorization: Digest username="REDACTED_AUTH_USERNAME", realm="REDACTED_REALM", nonce="REDACTED_OLD_NONCE", algorithm=MD5, uri="sip:REDACTED_REGISTRAR_IP:5060;transport=udp", response="REDACTED_DIGEST_RESPONSE"
Content-Length: 0

The registrar responds:

SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP REDACTED_FREESWITCH_IP:5080;rport=5080;branch=z9hG4bK_REDACTED
Proxy-Authenticate: Digest nonce="REDACTED_NEW_NONCE",algorithm=MD5,realm="REDACTED_REALM"
To: <sip:REDACTED_EXTENSION@REDACTED_REGISTRAR_IP>;tag=REDACTED_TAG
From: <sip:REDACTED_EXTENSION@REDACTED_REGISTRAR_IP>;tag=REDACTED_TAG
Call-ID: REDACTED_CALL_ID
CSeq: REDACTED_CSEQ REGISTER
Content-Length: 0

After this, FreeSWITCH does not send another REGISTER Expires: 0 using the fresh nonce from the 407.

Actual behavior

FreeSWITCH sends one unregister request:

REGISTER ... Expires: 0
Proxy-Authorization: Digest ... old/cached nonce ...

The registrar replies:

407 Proxy Authentication Required
Proxy-Authenticate: Digest nonce="new_nonce"

FreeSWITCH does not retry with:

REGISTER ... Expires: 0
Proxy-Authorization: Digest ... new_nonce ...

The gateway remains registered on the registrar side until the remote registration timeout expires.

Expected behavior

On receiving 407 Proxy Authentication Required for a gateway unregister transaction, FreeSWITCH should retry the unregister request using the new nonce:

REGISTER ... Expires: 0
407 Proxy Authentication Required
REGISTER ... Expires: 0 + Proxy-Authorization using fresh nonce
200 OK

This is especially important for registrars that always challenge unregister requests, or that reject stale/preemptive digest credentials and issue a new nonce.

Steps to reproduce

  1. Configure a Sofia gateway against a registrar that challenges unregister requests with 407 Proxy Authentication Required.

  2. Confirm the gateway is registered:

sofia status gateway gw_test
  1. Enable SIP trace:
sofia profile external siptrace on
  1. Run:
sofia profile external unregister gw_test
  1. Observe that FreeSWITCH sends REGISTER Expires: 0.

  2. Observe that the registrar responds with 407 Proxy Authentication Required and a new nonce.

  3. Observe that FreeSWITCH does not send the second authenticated REGISTER Expires: 0.

Related command behavior

The same issue is visible when using:

sofia profile external killgw gw_test

In that case, FreeSWITCH attempts to unregister, receives 407, and then deletes the gateway object before a successful authenticated unregister completes.

Observed log:

[NOTICE] sofia_reg.c:141 UN-Registering gw_test
...
SIP/2.0 407 Proxy Authentication Required
...
[NOTICE] sofia_reg.c:342 Deleted gateway gw_test

Gateway config shape

Relevant gateway parameters are approximately:

<gateway name="gw_test">
  <param name="username" value="REDACTED_EXTENSION"/>
  <param name="auth-username" value="REDACTED_AUTH_USERNAME"/>
  <param name="password" value="REDACTED_PASSWORD"/>
  <param name="realm" value="REDACTED_REALM"/>
  <param name="proxy" value="REDACTED_REGISTRAR_HOST:5060"/>
  <param name="register-proxy" value="REDACTED_REGISTRAR_HOST:5060"/>
  <param name="from-domain" value="REDACTED_REGISTRAR_HOST"/>
  <param name="extension" value="REDACTED_EXTENSION"/>
  <param name="register" value="true"/>
  <param name="register-transport" value="udp"/>
  <param name="expire-seconds" value="60"/>
  <param name="retry-seconds" value="10"/>
</gateway>

The issue also occurs when attempting a direct registration style without proxy, using only register-proxy.

Why this matters

Without a successful authenticated unregister, the registrar keeps the contact binding active until timeout. This causes operational issues when dynamically disabling or removing gateways, especially in systems that need to rapidly register/unregister many SIP accounts.

Lowering expire-seconds is only a workaround; it does not make unregister immediate or reliable.

Suggested fix area

The likely area is gateway unregister handling in:

src/mod/endpoints/mod_sofia/sofia_reg.c

FreeSWITCH should keep the gateway/register transaction alive long enough to complete the digest challenge flow for unregister, and should retry the Expires: 0 REGISTER after receiving 401 or 407 with a fresh nonce.

In particular, the expected flow should be:

REGISTER Expires: 0
407 Proxy Authentication Required
REGISTER Expires: 0 with fresh Proxy-Authorization
200 OK

For killgw, it may also be necessary to delay actual gateway deletion until the unregister transaction completes or fails definitively.

Workaround

Set a short registration expiry:

<param name="expire-seconds" value="60"/>
<param name="retry-seconds" value="10"/>

Then treat unregister as best effort:

fs_cli -x "sofia profile external unregister gw_test"
sleep 2
fs_cli -x "sofia profile external killgw gw_test"

However, this does not solve the actual issue when the registrar requires a fresh digest challenge response for unregister.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions