Extensions behind NAT can't hear each other

I am trying to setup a simple PBX to connect a few people in an office and a few remote teleworkers. For the most part my configuration works, but I am having difficulty making calls between the handsets if they are both located within the same network. The signalling works (the phones ring) but no audio is transmitted.

For example, user A and B are in the same office behind a Linksys E2500 router. User C is somewhere else in world. A or B can call C with no issues, but if A and B try to call each other, no audio is heard. Users A and B can both do echo tests at the same time.

The network topology looks roughly like this:

Asterisk Box <-> PIX Firewall <-> Internet <-> Linksys E2500 <-> Phone

My first thought was that it was the Linksys E2500 router. I tried testing with the SIP ALG feature both enabled and disabled but had the same result either way. I tried substituting a D-Link DIR-655 and had the same issues.

My next thought was that it was the PIX firewall. I’ve read that they are not especially good at handling SIP. I created a second Asterisk test machine in a VM on a different network that wasn’t behind a PIX. I had had the same issues.

Can anyone offer some suggestions? All the reading I’ve done indicates that this is a NAT issue, but I don’t know what else to try. I know that this has to be a fairly common deployment scenario and I know it should work.

Here is some info and config files that may be relevant.

OS: FreeBSD 9.0
Asterisk Version:








astetcdir => /usr/local/etc/asterisk
astmoddir => /usr/local/lib/asterisk/modules
astvarlibdir => /usr/local/share/asterisk
astdbdir => /var/db/asterisk
astkeydir => /usr/local/share/asterisk
astdatadir => /usr/local/share/asterisk
astagidir => /usr/local/share/asterisk/agi-bin
astspooldir => /var/spool/asterisk
astrundir => /var/run/asterisk
astlogdir => /var/log/asterisk

;verbose = 3
;debug = 3
;alwaysfork = yes               ; Same as -F at startup.
;nofork = yes                   ; Same as -f at startup.
;quiet = yes                    ; Same as -q at startup.
;timestamp = yes                ; Same as -T at startup.
;execincludes = yes             ; Support #exec in config files.
;console = yes                  ; Run as console (same as -c at startup).
;highpriority = yes             ; Run realtime priority (same as -p at
                                ; startup).
;initcrypto = yes               ; Initialize crypto keys (same as -i at
                                ; startup).
;nocolor = yes                  ; Disable console colors.
;dontwarn = yes                 ; Disable some warnings.
;dumpcore = yes                 ; Dump core on crash (same as -g at startup).
;languageprefix = yes           ; Use the new sound prefix path syntax.
;internal_timing = yes
;systemname = my_system_name    ; Prefix uniqueid with a system name for
                                ; Global uniqueness issues.
;autosystemname = yes           ; Automatically set systemname to hostname,
                                ; uses 'localhost' on failure, or systemname if
                                ; set.
;maxcalls = 10                  ; Maximum amount of calls allowed.
;maxload = 0.9                  ; Asterisk stops accepting new calls if the
                                ; load average exceed this limit.
;maxfiles = 1000                ; Maximum amount of openfiles.
;minmemfree = 1                 ; In MBs, Asterisk stops accepting new calls if
                                ; the amount of free memory falls below this
                                ; watermark.
;cache_record_files = yes       ; Cache recorded sound files to another
                                ; directory during recording.
;record_cache_dir = /tmp        ; Specify cache directory (used in conjunction
                                ; with cache_record_files).
;transmit_silence = yes         ; Transmit silence while a channel is in a
                                ; waiting state, a recording only state, or
                                ; when DTMF is being generated.  Note that the
                                ; silence internally is generated in raw signed
                                ; linear format. This means that it must be
                                ; transcoded into the native format of the
                                ; channel before it can be sent to the device.
                                ; It is for this reason that this is optional,
                                ; as it may result in requiring a temporary
                                ; codec translation path for a channel that may
                                ; not otherwise require one.
;transcode_via_sln = yes        ; Build transcode paths via SLINEAR, instead of
                                ; directly.
;runuser = asterisk             ; The user to run as.
;rungroup = asterisk            ; The group to run as.
;lightbackground = yes          ; If your terminal is set for a light-colored
                                ; background.
;forceblackbackground = yes     ; Force the background of the terminal to be
                                ; black, in order for terminal colors to show
                                ; up properly.
;defaultlanguage = en           ; Default language
documentation_language = en_US  ; Set the language you want documentation
                                ; displayed in. Value is in the same format as
                                ; locale names.
;hideconnect = yes              ; Hide messages displayed when a remote console
                                ; connects and disconnects.
;lockconfdir = no               ; Protect the directory containing the
                                ; configuration files (/etc/asterisk) with a
                                ; lock.

; Changing the following lines may compromise your security.
;astctlpermissions = 0660
;astctlowner = root
;astctlgroup = apache
;astctl = asterisk.ctl






include => kh-phones
include => kh-test
include => voipms-outbound

; Phone 1
exten => 110,1,Dial(SIP/kh-earonyk-home,10,m)
;same => n,VoiceMail(110@kh)

; Phone 2
exten => 120,1,Dial(SIP/kh-earonyk-cell,10,m)
;same => n,VoiceMail(120@kh)

exten => 200,1,Answer()
exten => 200,2,Echo()

exten => 201,1,Answer()
same => n,Playback(hello-world)
same => n,Hangup()

exten => 202,1,Answer()
same => n,Set(MyIPAddressIs=${CURL(http://www.whatismyip.org/)})
same => n,SayAlpha(${MyIPAddressIs})
same => n,Hangup()

exten => _1NXXNXXXXXX,1,Dial(SIP/${EXTEN}@voipms)
exten => _1NXXNXXXXXX,n,Hangup()
exten => _NXXNXXXXXX,1,Dial(SIP/1${EXTEN}@voipms)
exten => _NXXNXXXXXX,n,Hangup()
exten => _011.,1,Dial(SIP/${EXTEN}@voipms)
exten => _011.,n,Hangup()
exten => _00.,1,Dial(SIP/${EXTEN}@voipms)
exten => _00.,n,Hangup()

exten => OMITTED,1,Answer() ;your DID
same => n,Wait(1)
same => n,Playback(hello-world)
same => n,Hangup()

Try “directmedia=no”.

Also try setting the “localnet” and “externip” parameters.

That worked - thanks so much! I’ve been trying to figure that out for a while now.