Asterisk behind NAT with dynamic IP (Proxy or STUN)

Hello,

I’d like to run Asterisk behind NAT with a dynamic public IP address. Probably the easiest way is to edit external_media_address and external_signaling_address after each IP change. The problem is that I’d have to restart the daemon which could interrupt active internal calls.

Hence I tried to use siproxd as the outgoing SIP proxy. Fundamentally it worked fine, at least while testing with Linphone. Unfortunately, Asterisk uses the outgoing_proxy URI as the REGISTER URI, but siproxd cannot extract the real host for forwarding. Linphone sends its REGISTER query with the real host as the URI.

Linphone: (Proxy:sip:siproxd.com)
REGISTER sip:realsiphost.com SIP/2.0

Asterisk: (outbound_proxy=sip:siproxd.com)
REGISTER sip:siproxd.com SIP/2.0

siproxd config file (adapted):
outbound_domain_name = realsiphost.com
outbound_domain_host = realsiphost.com
outbound_domain_port = 5060

I thought about two Asterisk instances, one for internal calls and the other for outgoing purposes which I can restart regardlessly (in case of an IP change).

Has anyone a better idea?

You would need to add “;lr” to the end of your outbound proxy setting to enable loose routing. It won’t rewrite the request URI in that case.

After adding ;lr to the URI it works fine.

Thank you so much. Great support indeed!

Probably it has nothing to do with Asterisk: Unfortunately I cannot place outgoing calls.

INVITE sip:callednumber@sip.provider.com SIP/2.0
Via: SIP/2.0/UDP mypublicip:5069;branch=...
Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=...
From: <sip:mynumber@sip.provider.com>;tag=...
To: <sip:callednumber@sip.provider.com>
Call-ID: ...
CSeq: 18455 INVITE
Contact: <sip:mynumber@127.0.0.1:5060>
Content-Type: application/sdp
Allow: OPTIONS
Allow: SUBSCRIBE
Allow: NOTIFY
Allow: PUBLISH
Allow: INVITE
Allow: ACK
Allow: BYE
Allow: CANCEL
Allow: UPDATE
Allow: PRACK
Allow: REGISTER
Allow: REFER
Allow: MESSAGE
Supported: 100rel
Supported: replaces
Supported: norefersub
Max-forwards: 69
User-agent: Asterisk
Content-Length:   261

v=0
o=- 1480206569 1480206569 IN IP4 mypublicip
s=Asterisk
c=IN IP4 mypublicip
t=0 0
m=audio 7076 RTP/AVP 9 8 101
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:150
a=sendrecv

provider -> siproxd




SIP/2.0 403 Forbidden
Via: SIP/2.0/UDP mypublicip:5069;branch=...
Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=...
To: <sip:mynumber@sip.provider.com>;tag=...
From: <sip:callednumber@sip.provider.com>;tag=...
Call-ID: ...
CSeq: 18455 INVITE
Content-Length: 0

I believe sip:mynumber@127.0.0.1:5060 is the problem, because during registration sip:mynumber@mypublicip:5069 is used.

Asterisk -> siproxd at registration

Contact: <sip:mynumber@127.0.0.1:5060>

Asterisk -> siproxd at invitation

Contact: <sip:s@127.0.0.1:5060>

So is this a problem of Asterisk or of siproxd?

You haven’t told Asterisk its public IP address. Please see the documentation in sip.conf.sample for how to do that.

Because I want to use siproxd as my outgoing proxy which knows my public IP. Hence I wouldn’t have to restart Asterisk every time my IP changes.

The provider shouldn’t care about the user part of the Contact address. It is up to Asterisk to ensure that reaches the right place.

The outgoing proxy should be adding Record-Route to ensure that the provider can get back to you, and should use the public address.

Assumed my provider does really not care about the Contact header, what could be the problem instead?

See the INVITE above.

My idea was that the proxy registers the public IP and the INVITE cannot be assigned by my provider’s server because of the different host in Contact header (127.0.0.1).

I’m saying that, if the Contact header is the problem, the provider is broken.

I think you are using chan_sip. chan_pjsip will end a random code in the Contact header.

I think chan_sip will send the caller ID in Contact, so you could try setting the caller ID to be the same as your registered address.

No, I’m using chan_pjsip. My sip.conf is empty.

It’s because you are using a local proxy. The code finds the IP address that is being used to contact the target and uses that in the Contact so the contacted thing can reach back. I’m not familiar with siproxd but it should replace that value in the Contact header when going to the VoIP proxy, otherwise if they don’t do any NAT traversal then it would go to the wrong place.

I’ve double checked the RFC, and the proxy should not modify the Contact header. It should use Record-Route to ensure a return path.

Although, I suppose 403 could mean almost anything, normally a bad Contact header on an outgoing request doesn’t show up until the peer tries to re-INVITE, or close the call. (A bad Contact on a response tends to show up about 30 seconds after answer, when the ACK is timed out.

I think there has been the occasional request here for fine control of the Contact header because SIP implementations are, incorrectly, trying to read meaning into which the standards simply do not give it.

As 403 could mean what the ITSP wants it to mean, one really needs the ITSP to say why the call was rejected.

Also, I think the OP was speculating that the problem was related to sending s, rather than the incoming call extension, in the Contact header, but there is no requirement that these be the same.

The user portion of the Contact can be set using the contact_user option in an outbound registration.

As for your comment - this is both true and not true, it depends upon which interaction. In the case of a REGISTER a Record-Route doesn’t guarantee that subsequent requests will go through the proxy. Path was actually created for that purpose, but that requires remote support.

I think they are concerned about INVITE, rather than REGISTER. There are no symptoms on the REGISTER, but they are clutching at the disparity between the user on the REGISTER contact and that on the INVITE, and thinking that making the INVITE the same as the REGISTER might help.

Oh, with an INVITE. I now understand more.

@ast2301 Your problem is likely due to something siproxd is doing to the message or the fact a proxy is present and the provider not liking that. The INVITE you have provided is valid.

This is the diff between the Asterisk-siproxd connection and the siproxd-provider one.

 INVITE sip:callednumber@sip.provider.com SIP/2.0
+Via: SIP/2.0/UDP publicip:5069;branch=...
 Via: SIP/2.0/UDP localip:5060;rport;branch=...
 From: <sip:mynumber@sip.provider.com>;tag=...
 To: <sip:callednumber@sip.provider.com>
 Contact: <sip:mynumber@localip:5060>
 Call-ID: ...
 CSeq: 22937 INVITE
-Route: <sip:localip:5069;lr>
 Content-Type: application/sdp
-Allow: OPTIONS, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, REGISTER, REFER, MESSAGE
+Allow: OPTIONS
+Allow: SUBSCRIBE
+Allow: NOTIFY
+Allow: PUBLISH
+Allow: INVITE
+Allow: ACK
+Allow: BYE
+Allow: CANCEL
+Allow: UPDATE
+Allow: PRACK
+Allow: REGISTER
+Allow: REFER
+Allow: MESSAGE
-Supported: 100rel, replaces, norefersub
+Supported: 100rel
+Supported: replaces
+Supported: norefersub
-Max-Forwards: 70
+Max-forwards: 69
-User-Agent: Asterisk
+User-agent: Asterisk
-Content-Length:   262
+Content-Length:   261
 
 v=0
-o=- 1422859986 1422859986 IN IP4 localip
+o=- 1422859986 1422859986 IN IP4 publicip
 s=Asterisk
-c=IN IP4 localip
+c=IN IP4 publicip
 t=0 0
-m=audio 15882 RTP/AVP 9 8 101
+m=audio 7074 RTP/AVP 9 8 101
 a=rtpmap:9 G722/8000
 a=rtpmap:8 PCMA/8000
 a=rtpmap:101 telephone-event/8000

Maybe there is something special.

There is nothing that stands out that would result in a 403 from the remote side.

Perhaps the problem is quite simple and my provider is just not accepting proxies (meaning the added Via-header).

I should take a second Asterisk instance into consideration which operates as PBX, not as proxy.

Assumed I have an internal call via Asterisk. Can I reload external_media_address and external_signaling_address without interrupting my call? Certainly Asterisk would have to re-register at the provider with the its new public IP.

I don’t believe it’s possible.

If the “allow_reload” option is set on the transport then it can be reloaded. In the latest version if you also have the res_stun_monitor module configured and loaded it should also cause outbound registrations to get refreshed automatically. This wouldn’t impact any calls in progress.