Rewrite the "From" header in calls to remote extensions

Home user here, please forgive any imprecision in my terminology.

TL;DR: I want to know whether or not it is possible to have PJSIP rewrite “From” headers based on the transport interface that an outgoing INVITE routes through.


Background: I have a FreePBX on a VLAN behind NAT with half a dozen internal SIP clients that have worked perfectly together for years. Now, I have added a new external SIP client (on a cell phone). I did this by using a second PJSIP transport:

  • UDP/TCP on 5060 for the internal clients
  • TCP-TLS on 5061 for the external client

There were some false starts implementing all the necessary firewall exceptions, port forwarding, and dynamic DNS entries. But at this point, calls between internal clients, external clients, and my provider trunk all seem to work perfectly. I get stable bidirectional audio with only minor drop-outs when my phone provider’s NAT decides to switch the endpoint IP address mid-call.

The rewrite_contact functionality was critical in making all of this work, particularly the external IP Address and Signalling Port fields:

With everything configured “correctly”, PJSIP now rewrites the “Contact” header with my external IP address (75.XX.XX.XX) and transport when an internal client calls the remote client (147.XX.XX.XX):

INVITE sip:[email protected]:38870;transport=TLS SIP/2.0
Via: SIP/2.0/TLS 75.XX.XX.XX:25061;rport;branch=z9hG4bKPjf173c2ea-6037-43c3-9ce3-71acbd20dc06;alias
From: “simaril” sip:[email protected];tag=a4ee3802-59a9-4791-bc28-9ba3390b1e07
To: sip:[email protected]
Contact: sip:[email protected]:25061;transport=TLS
Call-ID: 1fb190ba-0345-4d4c-aa61-ae4afd1f3694
CSeq: 18474 INVITE
Allow: OPTIONS, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, MESSAGE, REFER
Supported: 100rel, timer, replaces, norefersub, histinfo
Session-Expires: 1800
Min-SE: 90
P-Asserted-Identity: “simaril” sip:[email protected]
Max-Forwards: 70
User-Agent: FPBX-16.0.40.7(18.9)
Content-Type: application/sdp
Content-Length: 476

However, the “From” header continues to show an internal address (10.XX.XX.XX IP). This means that when I redial from the external client, the invite gets lost. It’s a minor annoyance – I can delete the address portion and my SIP client is smart enough to dial “231” directly – but it would be nice to fix

I am aware of this forum thread that proposes setting “from_domain” for each of the affected extensions. But I don’t think the solution would be appropriate here because all of the internal extensions still need to call each other through the internal network interface. Half of my internal extensions are old Cisco phones that don’t even have access to DNS.

It seems logical to me that the “Domain the transport comes from” should be used to rewrite the “From” field, but it doesn’t seem to work that way. I can’t even find where those fields are stored or used by asterisk. My “pjsip.transports.conf” doesn’t even include a field value that matches “internaldomain.example.com”:

[0.0.0.0-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
allow_reload=no
tos=cs3
cos=3

[0.0.0.0-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
external_media_address=externaldomain.example.com
external_signaling_address=externaldomain.example.com
external_signaling_port=25061
ca_list_file=/etc/pki/tls/certs/ca-bundle.crt
cert_file=/etc/asterisk/keys/example.crt
priv_key_file=/etc/asterisk/keys/example.key
method=tlsv1_2
verify_client=yes
verify_server=yes
allow_reload=no
tos=cs3
cos=3

Is it unreasonable to expect that FreePBX / asterisk can rewrite the “From” header based on the outgoing transport parameters? Am I really the only one silly enough to set up FreePBX with two network interfaces and expect the clients to be able to inter-operate?

Or is it my SIP client application that’s doing the wrong thing? Should it be remembering and preferring the IP address in the “Contact” header (over the IP address in the “From” header) for its redial functionality?

If you got this far, thanks in advance for any light you can shed.

Most SIP clients ignore the From domain, except for those that support SIP URI dialing, sometimes called IP dialing. With luck, your client has a setting that disables that feature, which should cause it to use only the numeric part of From (and select the outbound account according to its dial plan).

What client are you using? Android or iOS? Are you open to using a different one that doesn’t have the issue?

I don’t believe it’s an issue in your case, but forwarding an external SIP port to a different internal port often causes trouble. Is there some reason why you didn’t set Port to Listen On to 25061 and forward 25061 → 25061?

I had wondered about the SIP client behavior. Being stubbornly determined to minimize the amount of user data I leak to the big tech companies, I haven’t left myself with that many options. I use baresip from F-Droid on GrapheneOS. I’ve evaluated most of the other SIP clients on F-Droid and baresip matched my requirements the best. I’d already created a request with the baresip project to see if they might be able to add a client option that ignores the from-domain.

As far as the port forwarding choice goes, there was no particular reason. I wanted a different port for a little bit of obscurity on my external interface, but saw no need to change the default on the internal interface.

Setting aside for a moment the specific question of the “from” header, I still haven’t been able to work out what the “Domain the transport comes from” settings actually do. They don’t seem to flow through to the /etc/asterisk/ configuration. Is this an unfinished feature?

The from domain is the domain of the SIP server. If you make a FQDN for the PBX such as pbx.mydomain.com that is the FQDN you put in the phone/client as the SIP Server. When the device sends requests out the From Header will have [email protected] when you type in digits to send a call to, the Request/To Headers will have [email protected]

Now once you hit the PBX, which is a Back-to-Back User Agent, the other side will have its own channel created to handle the call. If you are calling another extension then the From header will be based on that endpoints config at the PBX. The PBX will use its IP as the From domain unless the from_domain= setting has been set to a domain.

This is also how it works with your PSTN trunk endpoint, the PBX will use its IP as the From domain unless the from_domain= is set.

Why exactly do you need to touch the from domain part of all this?

As I understand it, “Domain the transport comes from” != “from_domain”. “Domain the transport comes from” is a PJSIP transport setting, while “from_domain” is an endpoint and/or trunk setting. I learned this from an asterisk community thread.

I wanted to rewrite the “from” header only for calls that go out on the PJSIP TLS interface, while calls on the TCP/UDP interface (i.e. the private network) continue to use IP address. It seemed logical after I found the options to rewrite the “contact” header in exactly this way. However, I’ve largely convinced myself that selectively rewriting the “from” header is not possible (unless the call routes through a trunk).

My question about “Domain the transport comes from” is actually an echo of a follow-up question in the same asterisk community thread. That question went unanswered, but I’m still curious. Whatever value “xyz” I put in the “Domain the transport comes from” fields, I can’t find “xyz” anywhere in /etc/asterisk/.

I know that my configuration is working in general because “xyz” in the “External IP Address/Port” fields maps to “external_signaling_address” and “external_media_address” in “/etc/asterisk/pjsip.transports.conf”.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.