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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions