PBX setup: registering two SIP trunks

Contents

Email to VeVoIP

This email provides an overview of the issues I encountered in setting up two trunks as SIP peers to the same provider. It provides background to the solution detailed below.

Here’s an interesting little problem, and I’m wondering if you have any insights to offer.

I have two DIDs with VeVoIP, peered to two different peers. For ease of administration at my end, I set up both peers on my FreePBX system as PJSIP trunks.

Now I suspect I could actually route both DIDs to the same peer and in Asterisk use the inbound DID to route the call to the correct phone. However, I want outbound calls to show the correct CID based on the nature of the call, and as far as I know the only way to do that is by setting up CID and CNAM information on the VeVoIP peer. And to do that I need to set up the peer as a trunk in FreePBX and use Outbound Routes to send a call to the apporpriate trunk.

My ISP is Shaw and they provided me with a Cisco DPC3825 DOCSYS router/switch/WiFi device. It works great, even automatically setting up a NAT for UDP packets on port 5060. Except … when Asterisk issues a SIP REGISTER request on either trunk, the router sees the requests as coming from the same IP address and allocates the same local port (61000) when setting up the NAT. Then I get a Big Scary Warning from VeVoIP saying I can’t do that. (“Two peers are using the same IP ADDR:PORT. This setup is not supported.”)

VeVoIP doesn’t seem to have the ability to accept SIP requests on any port other than 5060, so I couldn’t configure FreePBX to use port 5060 for one trunk and (say) 5760 for the other.

Being unable to find any way in the router to tell it to randomize the local port for NAT, I had to dig deeper. My FreePBX system runs as a VM within my main server, so I have two IP addresses available: the one assigned to the server and the one assigned to FreePBX. I configured one trunk to register directly with VeVoIP and the other to register with my server. After a lot of work, on the server I managed to configure iptables to rewrite the source and destination IP addresses on the SIP packets to forward them to VeVoIP. When these packets hit the router, it sets up a different local port so it can route the response back to the server, which in turn rewrites the addresses and sends them on to FreePBX. Now VeVoIP sees the SIP requests coming from different ports on my Shaw IP address.

It works, but it’s a bit clunky for my liking. So here are a couple of questions for you:

  1. Is it possible to set up one or both trunks as IAX instead of SIP peers?
  2. Can VeVoIP accept SIP requests on a port other 5060?

Setting up my server to NAT SIP requests from FreePBX

As noted above, the primary issue was my Shaw router acting as a sort of bottleneck for SIP packets. Because the REGISTER requests for the two trunks originated from the same IP address (the FreePBX system) and were going to the same destination and port (VeVoIP:5060), the router set up the same local port address on the outbound packets (aaa.bbb.ccc.ddd:61000.) This confused VeVoIP, because it saw the exact same IP address and port for two different peers. Sure, it could send the packets to aaa.bbb.ccc.ddd:61000, but then on my end the call would come in on wheicher trunk had most recently registered with VeVoIP.

The solution I came up with was to use a different source IP address for one of the trunks, which would case the router to allocate a different source port. Because the PBX system is running as a VM inside my home server, I already had a second IP address: the home server itself. So I updated the FreePBX trunks as follows:

Trunk Use Regsiter to server
1 Personal penguin:5060
2 Business VeVoIP:5060

Next I needed a way to get my server (penguin) to handle the SIP packets. The basic configuration was this:

  • Use iptables to re-write the destination IP address to VeVoIP (DNAT)
  • Use iptables to re-write the source IP address to the one used by penguin (SNAT) so it looks like the packet originated on the server instead of the PBX

With the above changes in place, the following happens:

  • In Asterisk, the trunk generates a REGISTER request and sends it to penguin
  • penguin re-writes the source and desttnation addresses as shown above, then sends the packet to the router because it’s now destined to an outside address
  • The router sees that it has to set up a NAT for the packet (local IP address is for penguin on 192.168.1.zzz and the internet address is aaa.bbb.ccc.ddd.) It examines the source IP address and, seeing it’s not from the PBX, realizes it needs to allocate a different source port than the one it was previoulsy using (for the PBX it was using port 61000; for penguin it chose 61202.) It then rewrites the source address again to aaa.bbb.ccc.ddd and sends the the packet to VeVoIP on port 5060.
  • VeVoIP processes the request and send a reply packet to aaa.bbb.ccc.ddd:61202
  • When my router gets the reply packet, is sees it came in on port 61202, so it router re-writes the destination address to penguin and sends the packet there.
  • For its part, penguin re-writes the destination address to pbx and sends the packet there
  • My PBX server gets the reply packet

Issues with firewalld

In theory all I needed to do was issue a couple of iptables commands to set up the SIP NAT. First, set up the destination NAT (it’s processed first by iptables):

VOIP_PROVIDER_IP="$(host proxy2.sip.vevoip.com | cut -f4 -d' ')"
PBX_IP="$(host penguin | cut -f4 -d' ')"
iptables -t nat -A PREROUTING -p udp --dport sip -s pbx -d penguin -j DNAT --to-destination $VOIP_PROVIDER_IP

Then set up the source NAT. This tells the Shaw router the request came from this computer and not ‘pbx’, causing the router to allocate a different source port:

iptables -t nat -A POSTROUTING -p udp --dport sip -s pbx -d $VOIP_PROVIDER_IP -j SNAT --to-source $PBX_IP

However, it wasn’t that simple. On CentOS 7, iptables is managed by firewalld, which sets up a rather comprehensive set of tables that by default deny access to services. So for starters I had to allow access to SIP:

firewall-cmd --zone=public --add-service sip
firewall-cmd --permanent --zone=public --add-service sip

Now I needed to tell firewalld to forward packets received on my server from FreePBX to VeVoIP. firewall-cmd has a --add-forward-port option, but that works only for packets that originated on the system where firewall-cmd ran. So I had to add a “rich rule:”

SERVER_IP="$(host penguin | cust -f4 -d' ')"
firewall-cmd --add-rich-rule "rule family='ipv4'
  source address='$PBX_IP' destination address='$SERVER_IP'
  forward-port port='sip' protocol='udp' to-addr='$VOIP_PROVIDER_IP' to-port='sip'"

Then I set up the source port rule:

firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 99 "-m mark --mark 0x64 -j SNAT --to-source $SERVER_IP"
Error: COMMAND_FAILED:
  '/usr/sbin/iptables-restore -w -n' failed: iptables-restore v1.4.21:
  The -t option (seen in line 2) cannot be used in iptables-restore.

Gah! This is actually a bug in firewall-cmd. I filed a bug for this issue with Red Hat 3 January 2020.