Choosing a softphone for iOS can be a little tricky. Power saving enforced by the mobile operating system means apps are suspended quickly after closing or locking the device. When the app is suspended, it drops any connection to the PBX, meaning you won’t be notified for inbound calls.

We get around this by using a service that includes push notifications.

The app provider typically registers on your PBX -> inbound calls get notified to them -> they send a push notification -> your device rings.

My home PBX is a rarely used project, but it’s still handy for labbing out configurations before setting them live in a production environment.

Softphone Choices Link to heading

There are a few choices for iOS softphones, including Zoiper and Bria, but these typically have subscriptions. I found some posts online for Groundwire with a one-off fee of £9.99 and thought I’d give it a shot.

Groundwire’s developer provides a service called SIPIS which allows remote registration and push notifications to the iOS device.

Setup Link to heading

The setup process on the app is pretty straightforward, but there are a lot of options on there!

Security Link to heading

Before I start - port forwarding has generally been restricted to known IPs inside address lists. Media ports (UDP 10000-20000) are considered safe to open to the outside world (source link below).

Exposed SIP services are constantly scanned for toll fraud (IRSF), so if you aren’t sure what you’re doing, keep it locked up.

If you make it to the end, there’s a section on setting up encryption for calls.

Signalling Port Forward Link to heading

Ports need to be forwarded on the edge firewall to the PBX to allow SIP registration for the app.

MikroTik makes this pretty easy, allowing you to add an Address List in the firewall for all of the IP addresses used by the app provider. Rather than manually adding all of the 32 IPv4 addresses, you can have the firewall do it for you, assuming it has DNS available:

/ip/firewall/address-list/add address=all.sipis.acrobits.cz list=SIP-SIGNAL-Groundwire 

Check it worked with:

/ip/firewall/address-list/print where list=SIP-SIGNAL-Groundwire

Then, have the ports forwarded to the PBX:

/ip/firewall/nat
add action=dst-nat chain=dstnat comment="PORT-FORWARD: PBX SIGNAL Groundwire" dst-port=5060 \
    in-interface-list=WAN protocol=udp src-address-list=SIP-SIGNAL-Groundwire to-addresses=\
    192.168.1.10 to-ports=5060

This left me in the position of the app ringing when the extension was dialled. It worked well with the app in foreground, but not background.

Hairpin NAT Link to heading

Hairpin NAT is required when the app has been in the background. The SIPIS service connects the app via the externally registered IP address of the PBX. This wouldn’t be an issue with a publicly accessible PBX or SIP service, but with a home PBX it’s locked up behind the firewall.

The app was slow to connect to the PBX when brought to foreground and showed a message push handshake on the status.

Setting the Groundwire app to the external IP of the PBX, then hairpin NAT, things get better and it allows the push notifications to work.

To limit the app to use RTP ports 10000-20000, go to: Advanced settings > Hacks > RTP Port End > 20000.

/ip/firewall/nat
add action=dst-nat chain=dstnat comment="Hairpin-NAT for Groundwire (SIP)" dst-address=\
    203.0.113.10 dst-port=5060 in-interface-list=!WAN protocol=udp to-addresses=192.168.1.10 \
    to-ports=5060
add action=dst-nat chain=dstnat comment="Hairpin-NAT for Groundwire (Media)" dst-address=\
    203.0.113.10 dst-port=10000-20000 in-interface-list=!WAN protocol=udp to-addresses=\
    192.168.1.10 to-ports=10000-20000

The app should now be able to register with SIPIS to get push notifications.

Media Ports and WireGuard Link to heading

With the external IP address of the PBX being used to connect to the PBX with hairpin NAT, it needed to be added to my VPN routes. I thought this would cause hassle as it’s also the VPN connection endpoint IP, but it has so far been OK.

Now the iOS device would ring when in background, but when the call connected it had no audio when off WiFi and connected via VPN into the network. This was an easy fix, forwarding ports 10000-20000 UDP to the PBX. This is listed as SAFE by FreePBX

/ip/firewall/nat
add action=dst-nat chain=dstnat comment="PORT-FORWARD: PBX MEDIA" dst-port=10000-20000 \
    in-interface-list=WAN protocol=udp to-addresses=192.168.1.10 to-ports=10000-20000

Result + Features Link to heading

A working softphone with no subscription!

I’ve populated the softphone with other extensions on the PBX and clicked on the Busy Lamp Field option, which seemed to work with no other configuration required.

This will be a handy tool when travelling to get a local telephone number, mixed with SMS forwarding from Twilio to AllQuiet via a webhook.

For larger scale deployments, it seems there is a provisioning tool available in the docs.

Bonus TLS Encryption Link to heading

TLS and SRTP are available on Groundwire. I’d recommend getting the basics working first, then making changes to add TLS.

You’ll need a valid TLS cert for this to work.

Firewall rules Link to heading

  • Hairpin rule, change UDP to TCP, change port 5060 to 5061.
  • Port forward, change UDP to TCP, change port 5060 to 5061.
  • Media ports stay the same.
  • Keep the address list for the port forwards; the SIPIS IPs remain the same.

App config Link to heading

  • Keypad > Settings icon > Accounts,
  • Change the port in Domain from 5060 to port 5061,
  • Advanced settings, Transport Protocol to tls (sips),
  • Scroll to Secure Calls, change both SDES Incoming and Outgoing to Required.
  • Go back a level, click Preferences > Security > TLS. Check Verify Certificates is disabled (or manually ignore a specific cert during a test call).

FreePBX Config Link to heading

  • Settings > Asterisk SIP Settings > chan_pjsip tab.
  • TLS/SSL/SRTP Settings section,
    • Select the appropriate certificate in the Certificate Manager menu,
    • Select tlsv1_2 as the method,
    • Set Verify Client to No,
    • Set Verify Server to No. (I had this set to yes, but it broke Twilio trunking with their wildcard cert.)
  • In the Transports section, set tls - 0.0.0.0 - All to Yes.
  • 0.0.0.0 (tls) section, check port is set to 5061.
  • Click on the General SIP Settings tab > Security Settings section,
    • Set Allow Anonymous Inbound SIP Calls to No,
    • Set Allow SIP Guests to No.
  • Connectivity > Extensions > change each extension as required > advanced tab,
    • Set Transport to 0.0.0.0-tls - this forces the extn to connect using TLS and disallows UDP,
    • Set Media Encryption to SRTP via in-SDP,
    • Set Allow Non-Encrypted Media (Opportunistic SRTP) to No,
    • Set Direct Media to No,
    • Verify that DTLS is disabled.

Test Link to heading

  • Check firewall rules that all port 5060 UDP rules are changed, only UDP 10000-20000 should remain.
  • Complete test calls, ensure that you see a padlock icon on the call screen. Let the app go background for a few minutes and try again to ensure that the new handshake has been completed with TLS.