Howwise RSS
VoIP & Phone Systems8 min read

Asterisk 30 Second Call Drop: Find the Lost ACK

Short answer

An Asterisk 30 second call drop with no ACK happens because the ACK to the 200 OK never reaches Asterisk, so it gives up at 64*T1 = 32 seconds and sends BYE. Capture the SIP trace, find which address the ACK was sent to, and fix that header.

Key takeaways
  • A BYE at about +32s after answer, with repeated 200 OK and no ACK, is the Timer H signature of a lost ACK, not a codec, RTP or session-timer fault.
  • The ACK goes to the Contact of the 200 OK, or to the Record-Route set, so a private IP in either header is the most common cause.
  • In PJSIP set external_signaling_address, external_media_address and local_net on the transport, and include every internal, VPN and VLAN subnet in local_net.
  • Compare tcpdump on the PBX with one on the far side or firewall to see whether the ACK was never sent, lost in transit, or received and ignored.
  • Verify by calling for over a minute from LAN, remote and trunk paths and confirming the ACK follows the 200 OK immediately.

Why does an Asterisk call drop after about 30 seconds?

An Asterisk 30 second call drop, where the call connects and then hangs up about half a minute later, almost always means a lost ACK. A SIP INVITE is a three-way handshake: INVITE, 200 OK, ACK. Asterisk sends the 200 OK and then waits for the ACK.

Because UDP can lose packets, Asterisk retransmits the 200 OK on a backoff schedule: 500 ms, 1 s, 2 s, then 4 s repeating. This is the RFC 3261 behaviour for INVITE server transactions.

The retransmissions stop at 64*T1, which is 64 x 500 ms = 32 seconds. With no ACK by then, the call is considered failed and Asterisk sends BYE. So a hangup at 32 seconds is the signature of a lost ACK.

That timing is what separates this from other faults. A codec mismatch fails at setup or gives silence. A session-timer problem usually shows at half the Session-Expires interval, often many minutes in. An RTP problem leaves the call up with no audio. A call that connects, even with audio in both directions, and dies at +32s is an ACK problem.

Audio can work because RTP flows to the addresses negotiated in SDP, independently of where SIP signalling goes. The call looks healthy until the timer fires.

SymptomLikely cause
BYE at +32s, 200 OK repeated in logACK lost or ignored (this page)
Silence from the start, call stays upRTP/SDP address problem
Drop at 15 or 30 minutes, or half of Session-ExpiresSession timer refresh failing
Drop at +30s to +60s with no 200 OK repeatsProvider billing or credit limit, or max call duration

How do I capture the trace that proves where the ACK is lost?

Start on the PBX. Enable the SIP logger, place a test call, and let it die.

Then capture packets at the PBX and, if you can, at the far side or firewall. Comparing both shows whether the ACK left the phone or provider, reached your firewall, and reached the PBX interface.

  1. Run pjsip set logger on (chan_sip: sip set debug on) and place the call.
  2. Look for the 200 OK repeated at roughly +0.5s, +1.5s, +3.5s, +7.5s, +11.5s and so on, with no ACK between them.
  3. Capture on the PBX: tcpdump -ni any -s0 -w /tmp/sip.pcap port 5060. Add the SIP TLS port 5061 or your custom ports if used.
  4. Capture at the same moment on the remote phone's network or the firewall WAN interface.
  5. Open the pcap in sngrep or Wireshark and note the Contact, Record-Route and Via headers of the 200 OK, and the destination of any ACK.
asterisk -rx "pjsip set logger on"
sngrep -d any port 5060
tcpdump -ni any -s0 -w /tmp/sip.pcap port 5060 or port 5061
# afterwards
asterisk -rx "pjsip set logger off"
Warning: SIP logs and pcaps contain credentials in REGISTER digests and phone numbers. Capture only during the test and delete files afterwards. Do not post them unredacted.

Which header decides where the ACK goes?

For a 2xx response, the caller builds the ACK from the dialog state. The destination is the Record-Route set (as Route headers) if the 200 OK has one, otherwise the Contact URI of the 200 OK. The Via and source IP of the original INVITE are not used.

So a broken call usually looks like this. The 200 OK is sent to the right place, because responses follow the Via header. But it advertises an address the caller cannot reach:

The comments mark the bad header. The caller sends its ACK to 192.168.1.10, which on the public internet is either dropped or delivered to someone else's LAN.

# BROKEN: Asterisk behind NAT, no external_signaling_address
SIP/2.0 200 OK
Via: SIP/2.0/UDP 203.0.113.50:5060;received=198.51.100.7   <- response goes here, fine
Record-Route: <sip:192.168.1.10;lr>                         <- private, ACK will be routed here
Contact: <sip:192.168.1.10:5060>                            <- private
   (200 OK repeats at +0.5s +1.5s +3.5s +7.5s ... no ACK)
   (BYE from Asterisk at +32s)

# FIXED
SIP/2.0 200 OK
Contact: <sip:198.51.100.7:5060>                            <- public address

ACK sip:198.51.100.7:5060 SIP/2.0                           <- arrives immediately after 200 OK

How do I fix the advertised address in PJSIP and chan_sip?

Asterisk rewrites Contact and Record-Route to the external address only when the destination is outside local_net. So the three transport values must agree with your real topology.

Every internal range must be listed, including VPN pools, VLANs and Docker bridges. If one is missing, internal callers receive the public address, which often fails because of no hairpin NAT. If local_net is too wide, remote callers receive the private one.

Endpoint settings then deal with the phone side. rewrite_contact=yes makes Asterisk send in-dialog requests to the source IP and port of the request rather than the Contact header. This helps phones behind NAT. It does not fix a wrong Record-Route, which is generated by Asterisk's own transport settings.

force_rport=yes answers to the source port, rtp_symmetric=yes sends RTP back to where RTP arrives from, and direct_media=no keeps Asterisk in the media path so phones do not exchange private addresses.

; pjsip.conf (FreePBX: Settings > Asterisk SIP Settings > Chan PJSIP)
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
external_signaling_address=198.51.100.7
external_media_address=198.51.100.7
local_net=192.168.1.0/24
local_net=10.8.0.0/24      ; VPN
local_net=172.16.20.0/24   ; VLAN

[remote-phone]
type=endpoint
transport=transport-udp
rewrite_contact=yes
force_rport=yes
direct_media=no
rtp_symmetric=yes

; chan_sip equivalent (sip.conf [general])
; externaddr=198.51.100.7
; localnet=192.168.1.0/255.255.255.0
; nat=force_rport,comedia
; directmedia=no
Tip: Reload with core restart now only if no calls are active; pjsip reload is enough for most transport changes but verify with pjsip show transports. In a Docker or cloud (AWS or GCP elastic IP) setup, the instance only sees its private address, so external_signaling_address is mandatory.

Where is the ACK lost: firewall, provider, proxy or transport?

Use the two captures to place the loss. The table maps what you see to the cause and fix.

If the ACK reaches the PBX interface in tcpdump but Asterisk keeps retransmitting, the packet arrives but is not matched. That points to the PJSIP endpoint or identify match, an ACL, or a stateful firewall on the host such as iptables or fail2ban blocking a second source IP.

Providers sometimes send the ACK from a different IP than the one the INVITE came from. Allow all of their signalling ranges in the firewall, in identify entries (match=) and in any ACLs, not only the INVITE source.

With proxies such as Kamailio or OpenSIPS, the ACK follows the Route headers. Use record_route() and fix_nated_contact(), and check that the Record-Route hostname resolves from the caller and does not point to a private IP. Look at the ACK's Route header in the trace: that is exactly where the ACK is being sent next.

Transport matters too. If Contact has transport=tcp or tls, the ACK needs an open connection or port 5061 reachable. A large INVITE over UDP may fragment, and fragments are often dropped by firewalls. Also check that bind addresses are not tied to the wrong interface.

Where the 200 OK goes / what the trace showsWhere the ACK is sentWhere it is lostFix
Contact or Record-Route has 192.168.x or 10.xTo the private addressNever reaches PBXexternal_signaling_address, local_net
Contact public, ACK leaves the phone, absent at firewall WANTo the public IPSIP ALG or NAT mapping expiredDisable SIP ALG, keepalives, qualify_frequency
ACK arrives at firewall WAN, absent at PBXCorrect addressFirewall or port forwardForward UDP 5060 (and 5061), allow from provider ranges
ACK arrives on PBX interface, 200 OK still repeatsCorrectEndpoint or identify mismatch, ACL, fail2banFix identify, ACL, unban IP
ACK sent to different portWrong portContact port rewritten wronglyforce_rport, rewrite_contact, check bind port
Contact transport=tls or tcpTCP or TLS connectionConnection closed or 5061 blockedOpen port, matching transport, or use UDP
Route header with unresolvable hostFails DNSProxyFix record_route and fix_nated_contact

What mistakes hide this problem instead of fixing it?

Raising timers or disabling session timers does not help. Timer H is part of the transaction layer, not a session timer, and extending it only delays the BYE.

Changing the RTP port range is irrelevant when the fault is SIP signalling. Audio working both ways is normal with a lost ACK, so do not conclude the problem is media.

Do not test only from the LAN. Local phones are inside local_net and never hit the NAT path. Test from each route: LAN, remote, VPN and trunk.

Leaving SIP ALG enabled on the router is a common repeat cause. Disable it on the router and any upstream modem, since it rewrites SIP headers inconsistently.

How do I confirm the fix worked?

Check the behaviour on every path, not just one.

  1. Place a call longer than 1 minute from a LAN phone, a remote phone and through each trunk.
  2. With pjsip set logger on, confirm an ACK appears right after the 200 OK and the 200 OK is sent only once.
  3. Check the Asterisk log for no repeated 200 OK and no BYE at +32s.
  4. Run pjsip show transports and confirm the external address and local_net are as configured.

Common questions

Why is it exactly 32 seconds and not 30?

The timer is 64*T1 with T1 = 500 ms, so 32 seconds. Users round it to about 30, which is why searches say 30 seconds.

Can a one-way audio problem and the 32 second drop share a cause?

Yes. Both often come from a private address advertised in SIP or SDP when NAT settings are missing. The SDP fix is external_media_address, and the SIP fix is external_signaling_address.

Does qualify or keepalive help?

Yes for phones behind NAT. Regular OPTIONS or qualify_frequency traffic keeps the UDP mapping open so that inbound requests and ACKs can pass. It does not fix a wrong Contact.

Does the problem occur with outbound or inbound calls only?

It can affect either, but it commonly affects calls where the far side has to send the ACK to Asterisk, so check the direction in the trace.

Related topics:asteriskpjsipsip-natfreepbx