Trunk - Connecting with the Outside

Table of Contents

A PBX for internal calls is all well and dandy, but the real power is connecting your PBX users with a broader community.

The key thing to remember when trying to diagnose your configuration for connecting with an external party, is that VoIP telephony on the ’network’ is broken into several pieces. Two important pieces are setting up the conversation (SIP) and deliverying the conversation (RTP).

A generalised simplification of the above is:

SIP is a peer to peer protocol that registers devices to each other. This let’s your PBX set where it will send trunk calls, likewise your ISP knows your address for sending calls to you. SIP is usually the easiest part to get working through the network firewalls as it is generally configured for a standard port (5060 UDP).

RTP is used to carry media (such as audio and video) between end-points. One port is used for the data stream and one port for the Real-Time Control Protocol (RTCP) from one end-point to the other. The same number of ports are required for traffic in the return direction. The two parties dynamically set the ports and both devices need to support the breadth of possible ports. All devices in between (such as firewalls) also need to allow the RTP traffic.

Common symptoms of misconfiguration include:

  • Phones connect no-one hears audio
  • Phones connect and only one party hears audio

Below are two example configurations we have successfully deployed at various sites.

Private IP Address

[Ref: Asterisk 10.12.1, Doxygen, OpenBSD 5.3]

Site Information:

Our PBX is up and running inside our network. To connect with the Internet, it has to go through a NAT/Firewall device. If you’re reading this guide, then presumably your first choice is an OpenBSD firewall. We want to use this PBX for making calls to the POTS (Plain Old Telephone System.)

We purchase SIP Trunk from an Internet Service Provider, and it is our task to connect our PBX through the Internet:

  • Send incoming calls to an internal extension
  • Send outgoing calls to the SIP Trunk provider

Our Provider gives us their Public IP Address for the service, and a few configuration settings we have to implement on our Asterisk box.

These requirements seem pretty easy, and obviously millions of people have already done that, so we dig into the documentation and get the early warning.

[Ref: Doxygen SIP]

;----------------------------------------- NAT SUPPORT ------------------------
; WARNING: SIP operation behind a NAT is tricky and you really need
; to read and understand well the following section.

When this works, it’s blindingly obvious. When it doesn’t, there’s a lot of head scratching. Use the Asterisk console and the log files as first step to diagnose your set up and if you still have problems, refer to our maintenance for other tools.

RTP Configuration

[Ref: Doxygen RTP, Voip-Info Wiki]

Set the range of RTP ports to meet the configuration of the devices connecting with your PBX, including the configuration required by our vendor/voip provider.

For each RTP port used you also open an RTCP port so a call can consume up to 4 RTP ports but practise may show more RTP ports being consumed than expected.

; RTP Configuration

The choice of range will effect the upper-limit of simultaneous calls, as well as resource consumption on your system.

The selected range also need to match the settings on your firewall.

One cause of misqueued audio (where only one party hears audio) is a firewall mismatch of the RTP Ports. Use a range in your firewall that encompasses the configuration of both your server and the service provider’s.

For example:

If your RTP configuration is:

  • Our Server 10,000 –> 20,000 and
  • Our provider 15,00 –> 60,000

We must set your firewall settings to support a range between 10,000 –> 60,000.

SIP Configuration

[Ref: Doxygen SIP]

We set our SIP Configuration as per the below.

File extract: /etc/asterisk/sip.conf

context = phones
allowoverlap = no
bindport = 5060
transport = udp
bindaddr = PBX_Private_IPAddress
disallow = all
allow = alaw
allow = ulaw
allow = gsm
allow = g729
useragent = Asterisk 10.12.1


The two new settings not seen when not needing to go through a NAT firewall to an ISP are:

* externip =
* localnet =

The doxygen documentation says it should be externaddr = whereas there’s lots of references to externip = on the Internet.

Note: externip = worked for me, and the SIP packet Header correctly used the IP Address I put in this setting. You should however use the officially documented setting.

From Doxygen SIP

; + whether it is talking to someone "inside" or "outside" of the NATted network.
;   This is configured by assigning the "localnet" parameter with a list
;   of network addresses that are considered "inside" of the NATted network.
;   Multiple entries are allowed, e.g. a reasonable set is the following:
;      localnet= ; RFC 1918 addresses
;   a. "externaddr = hostname[:port]" specifies a static address[:port] to
;      be used in SIP and SDP messages.

Our adaptation of the settings from our provider results in the below:

canreinvite = nonat
directmedia = no
directrtpsetup = no

type=peer allows us to not require user-account settings, but we are now responsible for use other tools, such as a firewall to restrict connections to our PBX for this provider.

host=VENDOR_Public_IPAddress is the IP Address or domain name given us by the Vendor.

permit=VENDOR_Public_SUBNET is one Asterisk method of restricting connections. We’re specifying a subnet of the Vendors VoIP services because in our situation some of the RTP traffic is sent through another host in the specified subnet.

canreinvite and directmedia are specified because the vendor wants canreinvite in the configuration information we send them, where directmedia is the current Asterisk way of implementing what they want.

From Doxygen SIP

;----------------------------------- MEDIA HANDLING --------------------------------
; By default, Asterisk tries to re-invite media streams to an optimal path. If there's
; no reason for Asterisk to stay in the media path, the media will be redirected.
; This does not really work well in the case where Asterisk is outside and the
; clients are on the inside of a NAT. In that case, you want to set directmedia=nonat.
;directmedia=yes                ; Asterisk by default tries to redirect the
                                ; RTP media stream to go directly from
                                ; the caller to the callee.  Some devices do not
                                ; support this (especially if one of them is behind a NAT).
                                ; The default setting is YES. If you have all clients
                                ; behind a NAT, or for some other reason want Asterisk to
                                ; stay in the audio path, you may want to turn this off.
;directrtpsetup=yes             ; Enable the new experimental direct RTP setup. This sets up
                                ; the call directly with media peer-2-peer without re-invites.
                                ; Will not work for video and cases where the callee sends
                                ; RTP payloads and fmtp headers in the 200 OK that does not match the
                                ; callers INVITE. This will also fail if directmedia is enabled when
                                ; the device is actually behind NAT.

Incoming calls are matched to dialplans in the context [from-trunk]

Outgoing calls are sent via Dial(…) to [ven_telephony]

Firewall settings: NAT

Our firewall settings to get the above traffic going through a NAT’d environment is shown below.

File extract: /etc/pf.conf

table <srv_pbx>        {}
table <ven_telephony>  {VENDOR_Public_SUBNET}

ports_sip  = "{5060}"
ports_rtp  = "{9999 >< 60001 }"

set limit states 30000
match in all scrub (no-df random-id)

antispoof log for {$lo_if,$inet_if,$srv_if}
pass quick on lo0

block drop log all
block log quick inet6

pass out quick on $srv_if inet tagged INET_SRV
pass out quick on $inet_if inet tagged SRV_INET nat-to ($inet_if:0) static-port

pass in on $srv_if inet proto {tcp, udp} from <srv_pbx> to <ven_telephony> \
    port $ports_sip tag SRV_INET
pass in on $srv_if inet proto udp from <srv_pbx> to <ven_telephony> \
    port $ports_rtp tag SRV_INET
pass in on $srv_if inet proto icmp from <srv_pbx> to <ven_telephony> \
    icmp-type echoreq tag SRV_INET
pass in on $inet_if inet proto {tcp, udp} from <ven_telephony> \
     to ($inet_if:0) port $ports_sip rdr-to <srv_pbx> tag INET_SRV 
pass in on $inet_if inet proto udp from <ven_telephony> \
     to ($inet_if:0) port $ports_rtp rdr-to <srv_pbx> tag INET_SRV
pass in on $inet_if inet proto icmp from <ven_telephony> \
     to ($inet_if:0) icmp-type echoreq rdr-to <srv_pbx> tag INET_SRV	 

The key points for the Packet Filter rules are:

  • Match the ports_sip and ports_rtp to the settings provided by your vendor/provider.
  • Match the ports_sip and ports_rtp to the settings you specify in rtp.conf
  • NAT to the same ip address specified in the sip.conf setting: externip =
  • pass out using static-port
  • Redirect all incoming from the Vendor to our PBX (do not NAT)

Public IP Address

[Ref: Asterisk, Doxygen, OpenBSD 5.1

Site Information:

Management have bought into the whole Voice over IP thing, and they’re not satisfied with just getting something cheap off the Internet. Management are buying a dedicated fibre link from your VoIP provider. The fibre drops into your office and you plug an ethernet cable from it into your ’equipment.’ Now, we have to set it up, for the same features as the above office.

Note: the same configuration scenario is relevant to linking to internal PBXs together.

RTP Configuration

[Ref: RTP]

Once again, the important thing with configuring the port range for RTP, is to match it to the requirements by your various SIP end-points.

; RTP Configuration

We have a very short range, which may have implications on our service.

SIP Configuration

There are minute differences between the two [general] sections for sip.conf

File extract: /etc/asterisk/sip.conf

context = phones
allowoverlap = no
udpbindport = 5060
tcpenable = no
transport = udp
disallow = all
allow = alaw
allow = ulaw
allow = gsm
allow = g729
useragent = Asterisk
videosupport = yes
directmediadeny =
registerattempts = 0
callcounter = yes
subscribecontext = default

We’ve again explicitly set the useragent = but apart from that, the only real difference is that we’re not specifying the externaddr =

type = friend
bindaddr = Our_Public_IPAddress
host = VENDOR_Public_IPAddress
port = 5060
deny =
permit = VENDOR_Public_SUBNET
directmedia = no
videosupport = no
context = from-trunk
canreinvite = no
dtmfmode = auto
qualify = yes
disallow = all
allow = alaw
sendrpid = pai
trustrpid = yes

For the Vendor/Provider SIP configuration we are specifying type = friend because that’s the setting given to us, but the behaviour is the same as type = peer as we do not need the username/secret details, and must restrict access by using *host = * and permit = to specify IP Addresses that can connect on this account.

directmedia = no

One setting that we did not have in our original configuration is directmedia = no. Although this has the same behaviour as canreinvite = no the correct setting for this version of Asterisk is to set directmedia = no.

We had no problems with canreinvite = no when people were calling into our phone system, or our people were callling out. But, as soon as someone called in and we transferred them out, we experienced the audio problem where only one party to the call can hear the other side.

Obviously, the answer is to make sure you use the settings specified for the version of Asterisk you are running. For Asterisk 1.8 the correct setting is:

directmedia = no

Firewall settings: nonat

The firewall configuration for a directly connected Public IP Address is very simple. Note, if it was not already apparent, we are running the firewall on the same box as the PBX/Asterisk.

table <ven_telepony> {VENDOR PUBLIC IP Addresses}
# itsp - Internet Telephony Service Provider

ports_sip  = "{5060, 4569, 5036}"
ports_rtp  = "{9999 >< 20001}"

antispoof log for {$lo_if, $lan_if, $itsp_if}
pass quick on lo0

block drop log all
block drop log quick inet6

# ~~ ITSP
pass in on $itsp_if inet proto {tcp, udp} from <ven_telepony> to ($itsp_if:0) port $ports_sip
pass in on $itsp_if inet proto udp from <ven_telepony> to ($itsp_if:0) port $ports_rtp

pass out on $itsp_if inet proto {tcp, udp} from ($itsp_if) to <ven_telepony> port $ports_sip
pass out on $itsp_if inet proto udp from from ($itsp_if) to <ven_telepony> port $ports_rtp

#~~ User LAN
pass in on $lan_if inet proto udp from any to ($lan_if:0) port $ports_rtp
pass in on $lan_if inet proto tcp from any to ($lan_if:0) port $ports_sip

pass out on $itsp_if inet  from ($itsp_if)  keep state (no-sync)
pass out on $lan_if inet from ($lan_if)  keep state (no-sync)

# - icmp
pass in  on $lan_if inet proto icmp to ($lan_if:0) icmp-type echoreq
pass in  on $itsp_if inet proto icmp to ($itsp_if:0) icmp-type echoreq
pass out on $lan_if inet proto icmp from ($lan_if) to any icmp-type echoreq
pass out on $itsp_if inet proto icmp from ($itsp_if) to any icmp-type echoreq