Incorrect IP in contact header

When connecting to FreePBX via PJSIP from outside the local network everything works just fine most of the time. But every now and then there is no sound on all endpoints. There are sometimes weeks in-between that problem occurs. After a reboot or typing

fwconsole restart

the problem is gone but that’s not a solution. I was able to figure out that FreePBX is using the internal ip address in the contact header instead of the external ip address.
I don’t really understand why this is just happening just sometimes. Maybe someone of you has an idea?

Have you tried this:

Inside of FPBX (UI): go to “SIP advanced settings”

Be sure: your external IP address is listed in the correct field(s).

@sawgood1000 I’m not sure which settings you mean, I can only find ‘Asterisk SIP setting’. Because I’m not using a static ip address I put the domain name in those fields which usually works flawlessly.

I also was able to find out that the problem seems to appear whenever the external ip address changes. For now I’m using a custom script that invokes the ‘fwconsole restart’ whenever the ip address changes but this is just a workaround for me.

In general: why not?
How come your team does not have a static IP for the outside WAN (external IP).

Having this would solve it all …

@sawgood1000 Well, I don’t have a team. This is just a personal project and not my work. I’m having a PBX at home.

Anyone here having an idea what I could do?

Yeah, I know off problems concerning NAT / Asterisk and pjsip. You may have a look here to get them hopefully solved. It’s unfortunately not that easy.

Thank you for your advice! I’m not sure this is the same problem I’m experiencing. I don’t have any problems when connecting to my trunks. The problem only affects the connection between my PBX and my remote clients.

How often does your external IP address change? What triggers it?

It happens usually every 24 hours and it’s triggered by the ISP. Unfortunately another ISP isn’t an option in this area.

If you are using dynamic dns (you said you were using your domain name) your ddns client needs to update in a timely fashion.

1 Like

As dicko wrote, you have to take care, that the dnsmanager is configured correctly and you have to take care, that the host name you’re using for dnsmanager always has the correct IP address.

I’d similar problems with the trunk registrations. I solved it on base of the configuration described at the link I mentioned in my previous post. Additionally, I’m actively controlling the used host name for dnsmanager and I’m actively reloading dnsmanager after the change has been done (I’m completely controlling my router myself - it’s fully my own router - not a bought one). It turned out, that it’s important to force asterisk to restart the relevant transport(s) by itself (it’s not a reload or something similar because transports can’t be reloaded). The previous active transport must close its connection itself and has to open a new one. Therefore, I’m forcing a pjsip unregister / register to be sure to get a new connection with the new external IP address. That’s why it’s important to not use UDP for signaling, but at least TCP or better TLS.

But in your case, asterisk acts not as UAC, but UAS. I don’t know any way to get a transport restarted as described above if asterisk acts as UAS at the moment but to restart the complete asterisk service. Would it be a problem, to restart asterisk at night after the pppoe restart has been done (and you host name used for dnsmanager has the correct new IP address)? It would be easiest to bind asterisk to pppoe and check for correct IP address before. If you do not have access to pppoe itself, you have to find another way to detect the change and take care to have the correct IP address for your host name used by dnsmanager before restarting asterisk.

1 Like

@dicko My DynDNS works flawlessly. It’s also no problem to connect via SIP. It’s just the part when SIP tries to negotiate the RTP transport. It’s also not even using an old IP address in the contact header, but instead just the internal IP address. That’s what makes it so weird. Why is it sending the internal IP address to a remote client?

@dirk2358 Thank you for your detailed answer. That’s actually what I was afraid to hear. Since I figured this out I wrote a script on another server that checks the external IP address regularly and submits changes to FreePBX which invokes a fwconsole restart. This works, but was for me more of a workaround, because it’s another single point of failure.
I also don’t like to use a full restart, because it’s everywhere mentioned as bad practice. I just hoped that there is another way to achieve that with on-board tools. When using chan_sip I didn’t have those problems, but I’d prefer not using chan_pjsip and chan_sip simultaneously.

But thank you all again for your ideas, I highly appreciate it!

This thread has recently become interesting to me, because of another thread where pjsip inappropriately sends Asterisk’s LAN address in the Contact header:

I suspect that there is a bug in Asterisk that may be affecting many users.

A few questions for the OP:

Can you cause this problem at will, for example by power cycling your modem or router? If not, does your external IP address change when you do this?

When the trouble occurs, does the request or response with the incorrect Contact header have an external address in the SDP? If so, is it the ‘new’ or the ‘old’ address?

When the trouble occurs, have you tried issuing commands (at the Asterisk command prompt) such as
pjsip show transports
pjsip show transport 0.0.0.0-udp
pjsip show endpoint (extension affected by the problem)
If so, please post those results.

Somewhat off topic: An IP address change will certainly drop any calls in progress, and will likely also prevent them from being quickly re-established. Does your system have any measures to prevent that from happening, for example forcing a router or modem restart at 3 AM every day?

Also, for a small system with external extensions, I would normally recommend using a cloud PBX, rather than on-site. Even without technical issues, that is generally more robust; in a power or internet outage, external extensions would continue to function normally. Why have you not considered that?

@Stewart1 That seems to be the same problem!

I tried disconnecting and reconnecting my modem which caused a new IP address, but now it’s working. In the Asterisk CLI there is also an entry dnsmgr_refresh: dnssrv: host 'XXXXXXXXXX' changed from XXX.XXX.XXX.XXX:0 to YYY.YYY.YYY.YYY:0.

When the trouble occurs I only found the IP address of the remote extension as well as the internal IP address of the server in the Contact header. From and To header use the domain name.

I will try those commands when I’ll notice the problem the next time. But I’m using 0.0.0.0-tls instead of 0.0.0.0-udp even though I don’t think this should make a difference.

I know about this problem and I’m absolutely not happy with my current solution, but right now I don’t see any other way. A modem restart takes a long time, but a simple disconnect and reconnect isn’t possible with this model.

I mentioned it earlier already, but it’s more of a personal project. I’m having a PBX at home. I know other people do this as their work, for me it’s just interesting to learn about these things. But you’re absolutely right, if I were running a business I would exactly do it as you said.

This could be a very bad action on DSL lines regarding DSL sync parameters, which are managed by DLM. Chances are high that your profile is revised down and you therefore suffer a throughput decrease. On the other side, it’s definitely not sure to be increased again after you stoped doing things like that … .

You must take care, that Asterisk / pjsip handles the changed IP address correctly and as quickly as possible. It is possible (though not very nice) - I know it, because I’m doing it without restarting anything :slight_smile: myself here.

I thought again about this issue and had an idea. Could it be possible that the IP address gets resolved behind the NAT which is why it becomes the internal IP address instead of the external IP address? It still doesn’t explain why it’s happening intermittent, but why it could happen at all.

@dirk2358 That’s interesting. Could you elaborate why this would happen or point to some documentation about this process?
Is this way you mentioned ‘without restarting anything’ what is described here https://www.ip-phone-forum.de/threads/asterisk-pjsip-und-nat-nicht-so-einfach-wie-man-glaubt.310575/?

Well, part of. Another important part is this one.

But I think I should tell something about the basic theory behind to get a better understanding of how things are working together.

What’s the goal?
Achieving as much security and availability by design. This is basically done by “divide et impera”. Therefore, lets begin to divide … .

What should be divided?
There are two “objects” to handle: your phones (FreePBX calls them “Extensions”) calling to each other and on the other side the way to the world, provided by your SIP provider (FreePBX calls it “Trunk”).

What’s the technical difference between a Trunk and an Extension? An Extension (= phone) has to register to FreePBX (-> meaning: Asterisk acts as server) - whereas a Trunk registers itself to the SIP provider (meaning: Asterisk acts as client).

From a network perspective, this means:
Extension: The Phone starts the connection to Asterisk - Asterisk has to provide a listener to allow the opening of new incoming IP connections.
Trunk: Asterisk itself starts a connection as client to the SIP-Provider (no need for a listener at all nowadays by using flows).

What exactly is responsible for the network connectivity?
It’s the transport, which is primarily a function of pjsip, which is used by Asterisk.

The question now is: how to separate Extensions and Trunks?
The answer: Provide different transports to Extensions and Trunks (and even different transports for different trunks). This provides the ability to easily use different IPs or even Networks or protocols for each “object”.

Why is it useful to provide different transports: because it’s possible to kind of “restart” a transport individually without influencing other connections.

Ok - coming back to your problem here:
You should define an own transport for your trunk in pjsip.transports_custom.conf. E.g. (here: tls):

[firstTrunk]
type=transport
protocol=tls
bind=192.168.13.27:0 # That's the IP of your interface you're using for NAT - the transport for your extensions should use another IP.
ca_list_file=/etc/pki/tls/certs/ca-bundle.crt
method=tlsv1_2
verify_server=yes
allow_reload=no
tos=0xb8
cos=3
external_media_address=[your FQDN to external IP]
external_signaling_address=[your FQDN to external IP]
local_net=192.168.0.0/16
nobind=1 # This can be used only, if you apply and correctly rebuild Asterisk / pjsip with the nobind patch mentioned [here](https://www.ip-phone-forum.de/threads/asterisk-pjsip-und-nat-nicht-so-einfach-wie-man-glaubt.310575). It greatly improves security, because there isn't any way any more to achieve your server from outside - no need for fail2ban.

Next step is to bind the trunk configuration to the desired transport. This must be done manually, too in
pjsip.endpoint_custom_post.conf

[your_endpoint_name](+type=endpoint)
transport=firstTrunk
...

In pjsip.registration_custom_post.conf

[your_endpoint_name](+type=registration)
transport=firstTrunk

If you got this working (i.e.: your trunk registers successfully to your SIP provider) and you’re able to place calls and receive calls (and you verified in the SIP trace, that all values in the SIP headers are correct), you are at the point to start the “reconnect” tests, after your external IP has changed.

Your first job at this moment is: detect the change (there are several ways to detect it - depending on your local conditions)! If you detected the change, take care that the “your FQDN to external IP” already contains the new external IP-address.
Next: refresh the external IP-address to use by asterisk by refreshing the DNS-manager:

/usr/sbin/asterisk -x "dnsmgr refresh"

Now, Asterisk knows the new external IP.
Next and last step is to “force” a restart of the transport used by this trunk definition (I’m waiting 1 second after the dns manager restart):

/usr/sbin/asterisk -x "pjsip send register *all"

What’s happening now?
Asterisk uses the existing connection (remember the “flow”) to register to the trunk. This must fail, because this connection doesn’t exist any more (remember: you’re external IP changed).
Therefore, Asterisk times out, pjsip closes this connection and restarts the TCP / TLS connection from scratch by sending SYN. Voila - you’re done.
To speed up the timeout and the restart of the trunk transport, apply this configuration to pjsip.registration.conf (this can be done with the normal GUI interface of FreePBX in the trunk definition - “general retry interval”):

retry_interval=10 ; (in type=registration) - or shorter

How to debug it?
You can see it in the REGISTER package: There is a new port and the new external IP address used in the Via header (compared to before). If you enabled pjsip logging, you will find entries like these (here for Deutsche Telekom AllIP):

[2021-10-10 19:16:09] DEBUG[13990] pjproject:       tlsc0x7f88a431df38 TLS client transport created
[2021-10-10 19:16:09] DEBUG[13990] pjproject:       tlsc0x7f88a431df38 TLS transport 192.168.13.27:51281 is connecting to tel.t-online.de:5061...
[2021-10-10 19:16:09] DEBUG[13989] pjproject:       tlsc0x7f88a431df38 TLS transport 192.168.13.27:51281 is connected to tel.t-online.de:5061

And you will see entries like these, which close existing connections:

[2021-10-10 19:26:48] DEBUG[13989] pjproject:       tlsc0x7f88a4309398 TLS connection closed
[2021-10-10 19:26:48] DEBUG[13989] pjproject:          sip_transport.c Transport tlsc0x7f88a4309398 shutting down, force=0
[2021-10-10 19:26:48] DEBUG[13989] pjproject:       tlsc0x7f88a4309398 TLS transport destroyed with reason 470006: EVP lib

How to activate pjsip logging:
Add to logger_logfiles_custom.conf:

pjsip.log => debug

This creates a pjsip log file pjsip.log in /var/log/asterisk

Why is it necessary to do all those things described here? Because dynamic IPs are mostly not supported by Asterisk at all and pjsip doesn’t fully implement RFC 5626. As an example: pjsip implemented a TLS or TCP ping (to keep open NAT gateways) - but the (missing) answer isn’t evaluated. If they would do this, it wouldn’t be necessary at all to do many of the steps mentioned here … .

Summary:
The described way shows how to securely set up a trunk connection and how to handle a change of the external IP address with NAT evolved without restarting anything and without breaking internal calls by separating Extensions and Trunks by using different transports and IPs / networks.

Disclaimer:
I hope, I didn’t forget some things I additionally did to get it working :slight_smile: - Hope it helps.

The definition of a trunk is always difficult, because it is not a concept used by SIP. However, I’d suggest that the real definition used by FreePBX is based on the ability to send digits in both directions, whereas extensions can only send them towards Asterisk.

Registration is not a requirement, and the client server distinction above is only relevant to registration. Asterisk is a client to an extension when handling a call to that extension.

I’d also note that flows will also be disrupted when the provider takes their 24 hourly anti-server measures.

@dirk2358 Wow, that’s amazing! Thank you very much for these detailed instructions! I think this could be helpful for many other people, too.

You mentioned that forcing a router or modem restart every day

On the Link you provided about this DLM I couldn’t find much information on how it works. Am I right that in this case of a restart, DLM would downgrade the performance to achieve a higher stability, because it sees the restart as a connection issue?

I actually noticed that it’s not possible to setup different transports that use the same protocol. Maybe this will come in a future version of FreePBX.

I will definitely try that out as soon as this issue occurs the next time so I can get the requested logs for @Stewart1. Unfortunately after getting a new IP address every single day it stopped a few days ago and I’m stuck with the same IP address and a flawlessly working FreePBX, so I cannot get those logs yet.