Skip to content

Conversation

@sobomax
Copy link
Contributor

@sobomax sobomax commented Dec 1, 2025

Summary
Port add_contact_alias() and handle_ruri_alias() functions

Details
Those are slightly better version of the fix_nated_contact() originating from Kamailio.

The problem with fix_nated_contact() is that it could cause RURI for in-dialog requests contain a different IP address as compared to the Contact in the initial INVITE.

Most endpoints are fine with that, however tere are some, notably MS Teams, which would reject such request with:

SIP/2.0 500 Internal Server Error
Reason: Q.850;cause=47;text="76a7afc3-d033-4988-9000-f70b41e4db1b;RURI in request has invalid FQDN value"

The full exchange when using fix_nated_contact() is as follows:

UA->OpenSIPS (initial INVITE):

opensips[NNNN]: RECEIVED message from 10.2.80.32:5060:
INVITE sip:[...]
Contact: <sip:[...]@10.2.80.22:5060>
                    ^^^^^^^^^^

OpenSIPS->UA:

SIP/2.0 100 Giving it a try
SIP/2.0 200 OK

UA->OpenSIPS:

ACK sip:[...]

OpenSIPS->UA (re-INVITE):

opensips[NNNN]: SENDING message to 10.2.80.32:5060:
INVITE sip:[...]@10.2.80.32:5060 SIP/2.0
                 ^^^^^^^^^^

UA->OpenSIPS:

SIP/2.0 500 Internal Server Error

Solution
Use add_contact_alias() in the INVITE/200 OK paths and handle_ruri_alias() in in-dialog request path.

UA->OpenSIPS (initial INVITE):

opensips[NNNN]: RECEIVED message from 10.2.80.32:5060:
INVITE sip:[...]
Contact: <sip:[...]@10.2.80.22:5060>
                    ^^^^^^^^^^

OpenSIPS->UA:

SIP/2.0 100 Giving it a try

OpenSIPS->B2BUA (initial INVITE):

opensips[NNNN]: SENDING message to [...]:
INVITE sip:[...]
Contact: <sip:[...]@10.2.80.22:5060;alias=10.2.80.32~5060~1>
                    ^^^^^^^^^^

B2BUA->OpenSIPS (re-INVITE):

opensips[NNNN]: RECEIVED message from [...]:
INVITE sip:[...]@10.2.80.22:5060;alias=10.2.80.32~5060~1 SIP/2.0
                 ^^^^^^^^^^

OpenSIPS->UA (re-INVITE):

opensips[NNNN]: SENDING message to 10.2.80.32:5060:
                                   ^^^^^^^^^^
INVITE sip:[...]@10.2.80.22:5060 SIP/2.0
                 ^^^^^^^^^^

Compatibility
Should not be any if used correctly. Special test case for the voiptests has been created and will be enabled once the change is merged into the opensips/master.

@sobomax sobomax requested a review from liviuchircu December 1, 2025 20:54
@github-actions
Copy link

github-actions bot commented Jan 1, 2026

Any updates here? No progress has been made in the last 30 days, marking as stale.

@github-actions github-actions bot added the stale label Jan 1, 2026
Those are slightly better version of the fix_nated_contact()
originating from Kamailio.

The problem with fix_nated_contact() is that it could cause
RURI for in-dialog requests contain a different IP address as
compared to the Contact in the initial INVITE.

Most endpoints are fine with that, however tere are some,
notably MS Teams, which would reject such request with:

SIP/2.0 500 Internal Server Error
Reason: Q.850;cause=47;text="76a7afc3-d033-4988-9000-f70b41e4db1b;RURI in request has invalid FQDN value"

The full exchange when using fix_nated_contact() is as follows:

UA->OpenSIPS (initial INVITE):

opensips[42757]: RECEIVED message from 10.2.80.32:5060:
INVITE sip:[...]
Contact: <sip:[...]@10.2.80.22:5060>
                    ^^^^^^^^^^

OpenSIPS->UA:

SIP/2.0 100 Giving it a try

SIP/2.0 200 OK

UA->OpenSIPS:

ACK sip:[...]

OpenSIPS->UA (re-INVITE):

opensips[42759]: SENDING message to 10.2.80.32:5060:
INVITE sip:[...]@10.2.80.32:5060 SIP/2.0
                 ^^^^^^^^^^

UA->OpenSIPS:

SIP/2.0 500 Internal Server Error
@stale stale bot removed the stale label Jan 2, 2026
@sobomax sobomax requested a review from razvancrainea January 2, 2026 17:30
@bogdan-iancu
Copy link
Member

Hi @sobomax , thanks for the contribution here. Here are some first thoughts:

  • yes, indeed, the problem addressed by this PR is real
  • there are already ways to address the problem described here:
    ** use the topo hiding with dialog module - it is doing more or less the same as you manually do , but is a simpler and more elegant way
    ** you can achieve 100% the same results with scripting, by adding the extra Contact param via fix_nated_contact() (see uri_params func param, where you can store as base64 encoded the full original URI); on sequential requests, it's a simple transformation to fetch (from URI param) and replace the RURI.
    ** even simpler, if using the dialog module (without TH), you can store the received Contact URI into a dlg val and restore it later, it something trivial.
  • storing data into the SIP req is not always the best approach; beside leaking network information, you rely on the end points to correctly do their jobs (like mirroring that param) - history taught us (see the RR/Route mess) that reality is a bit different.

The benefit of these new functions is (as far as I can understand) to simplify a bit the scripting IF you do NOT WANT to use dialog support. Otherwise, it may complicate even more the scripting, as the user has to use more functions. Maybe we can add a new flag to fix_nated_contact(), in order to add this new param ? And we can use the "maddr" param (standard) which is automatically recognized by OpenSIPS (in routing RURI) for overriding the actual RURI domain/port

@bogdan-iancu bogdan-iancu self-assigned this Jan 8, 2026
@bogdan-iancu
Copy link
Member

I might have said something wrong in the above comment - the maddr param is of no use here, as it works exactly the opposite - it acts as a outbound proxy, without changing the host part; while we need to actually change the host part of the RURI. So please ignore that part.
On the other hand, as OpenSIPS is a proxy and we are in the NAT traversal area, it is mandatory for OpenSIPS to stay in the path of the dialog for all the sequential requests - this translates into doing dialog+TH (but you do not want to use this), or to do record_route. So, the only applicable scenario is doing RR + LR -> why nor incorporate this "fixing" into the loose_route part ?

@sobomax
Copy link
Contributor Author

sobomax commented Jan 13, 2026

Hey @bogdan-iancu thanks for a review.

Well to answer some of your remarks:

  1. Using dialog / topology hiding. In our case OpenSIPS is used as a trusted "front-end" for the dialog-stateful B2BUA. For that reason neither of options is very compelling: first for the performance impact and the second is not desirable since B2BUA assumes and actually requires full transparency of the front-end (i.e. OpenSIPS) in terms of headers in order to perform many of its functions such as IP auth for example. Also, some of your concerns are not applicable such as "leaking network information", we actually want to leak all of it including NAT status since the next hop is ALWAYS the trusted system. This configuration survived test of time (20 years and counting), so there is no much reason for us to switch it when a single sub-100 lines function can fix the issue.

  2. Yes, we rely on RR/LR in our setup, but I don't see how this mechanism would help us in this case.

13 Jan 11:14:34.947/GLOBAL/opensips[34018]: RECEIVED message from 192.168.23.43:5063:
INVITE sip:bob_nated_contact@192.168.23.52 SIP/2.0
Via: SIP/2.0/UDP 192.168.23.43:5063;rport;branch=z9hG4bK0e1a05adcafbc8effcc47a2db336c6f9
From: "Alice Smith" <sip:alice_nated_contact_ipv4@192.168.23.43>;tag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z
To: <sip:bob_nated_contact@192.168.23.52>
Call-ID: ?8R31E/uuC0".-b.tYlf1%UVh}ufgSbA@fB[Ak_7]!R}a\V\?
CSeq: 200 INVITE
Contact: <sip:alice_nated_contact_ipv4@192.168.255.10:5090>
13 Jan 11:14:34.949/GLOBAL/opensips[34018]: SENDING message to 192.168.23.52:5065:
INVITE sip:nat-bob_nated_contact@192.168.23.52 SIP/2.0
Record-Route: <sip:192.168.23.52;lr;ftag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z>
Via: SIP/2.0/UDP 192.168.23.52:5060;branch=z9hG4bK8e76.63247fa3.0
Via: SIP/2.0/UDP 192.168.23.43:5063;received=192.168.23.43;rport=5063;branch=z9hG4bK0e1a05adcafbc8effcc47a2db336c6f9
From: "Alice Smith" <sip:alice_nated_contact_ipv4@192.168.23.43>;tag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z
To: <sip:bob_nated_contact@192.168.23.52>
Call-ID: ?8R31E/uuC0".-b.tYlf1%UVh}ufgSbA@fB[Ak_7]!R}a\V\?
CSeq: 200 INVITE
Contact: <sip:alice_nated_contact_ipv4@192.168.255.10:5090;alias=192.168.23.43~5063~1>
13 Jan 11:14:43.000/GLOBAL/opensips[34018]: RECEIVED message from 192.168.23.52:5065:
INVITE sip:alice_nated_contact_ipv4@192.168.255.10:5090;alias=192.168.23.43~5063~1 SIP/2.0
Via: SIP/2.0/UDP 192.168.23.52:5065;rport;branch=z9hG4bK435199dbcde120292f9326df004bdebc
Route: <sip:192.168.23.52;ftag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z;lr>
From: <sip:bob_nated_contact@192.168.23.52>;tag=9bf08bf43403673c41b92d1c1432026f
To: "Alice Smith" <sip:alice_nated_contact_ipv4@192.168.23.43>;tag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z
Call-ID: ?8R31E/uuC0".-b.tYlf1%UVh}ufgSbA@fB[Ak_7]!R}a\V\?
CSeq: 100 INVITE
13 Jan 11:14:43.000/GLOBAL/opensips[34018]: SENDING message to 192.168.23.43:5063:
INVITE sip:alice_nated_contact_ipv4@192.168.255.10:5090 SIP/2.0
Via: SIP/2.0/UDP 192.168.23.52:5060;branch=z9hG4bK158.32d32ea7.0
Via: SIP/2.0/UDP 192.168.23.52:5065;received=192.168.23.52;rport=5065;branch=z9hG4bK435199dbcde120292f9326df004bdebc
Max-Forwards: 69
From: <sip:bob_nated_contact@192.168.23.52>;tag=9bf08bf43403673c41b92d1c1432026f
To: "Alice Smith" <sip:alice_nated_contact_ipv4@192.168.23.43>;tag=0pxgMeL7tSo8g5Tea6wTcfes0yCD-R.Z
Call-ID: ?8R31E/uuC0".-b.tYlf1%UVh}ufgSbA@fB[Ak_7]!R}a\V\?
CSeq: 100 INVITE
Contact: Anonymous <sip:192.168.23.52:5065>

Bottom line this works and solves our (and probably someone else's problems). Last but not least is that we have already started deploying it into production, so some quite non-negligible effort went into validation and testing.

Wholistically at this stage of SIP vs NAT it's clear to me that there will be no "one fits all" NAT handling logic, so this mechanism in my view is another useful tool in that growing toolbox. If someone comes up next week with a more elegant solution using RR or anything else not involving switching into a full dialog-stateful mode we might be interested to test that. But I cannot promise even that, let alone reworking and re-testing already perfectly functional solution. Thanks for understanding.

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