paulgorman.org/technical

Basic Asterisk Configuration

March 2016

(Note: much of the following notes show the old chan_sip driver. The new pjsip is covered in the final section.)

In Asterisk, there’s no distinction between a station phone and a trunk — everything is a Channel. The channels are defined in /etc/asterisk/sip.conf.

All channels get passed through the Dialplan. The dialplan is defined in /etc/asterisk/extensions.conf.

An Asterisk extension isn’t like a number on a traditional PBX — it’s more like a named group of instructions or a function/script name. An extension might ring a phone, but it might kick of a series of other actions instead.

Find Asterisk config files in /etc/asterisk/.

Find Asterisk data files (including music on hold) in /var/lib/asterisk/ or /usr/share/asterisk/. The file location is specified in /etc/asterisk/asterisk.conf.

Voicemail and call recordings are stored in /var/spool/asterisk/.

Asterisk logs to /var/log/asterisk/.

The documentation, if installed, can be found either in /var/lib/asterisk/documentation/ or /usr/share/doc/asterisk-doc/. The documentation contains well-commented sample config files.

Connect to a running Asterisk daemon:

% asterisk -r
% asterisk -rTvv

sip.conf can be reloaded from the Asterisk console

CLI> module reload chan_sip.so

The /etc/asterisk/modules.conf file controls which modules get loaded. By default, this contains the line ‘autoload=yes’, which loads all modules found in /usr/lib/asterisk/modules/. We may want to save resources by preventing some modules from loading, like ‘no => foo.so’.

Recommendation: name phones by their MAC address, not the person sitting at the desk. (Not sure about this one.)

Dialplan

The four concepts of a dialplan:

The “same =>” shorthand operator:

This:

exten => 123,1,Answer()
exten => 123,n,doStuff()
exten => 123,n,doMore()
exten => 123,n,Hangup()

can be abbreviated as:

exten => 123,1,Answer()
	same => n,doStuff()
	same => n,doMore()
	same => n,Hangup()

(Indentation is optional.)

Variables can be used:

PI=3.141592
Dial(${PI})

By convention globals are UPPERCASE, channel variables are camelCase. System environment variables can be accessed like:

${ENV(foo)}

Asterisk sets some variables:

${EXTEN}    Current extension
${EXTEN:1}  Extension omitting first numeral (subscript one to end of number)
${EXTEN:-4:4}  Start four digits from end, and return four digits (i.e. last 4 of number)

Pattern matching. Patterns start with an underscore.

    X    matches 0-9
    Z    matches 1-9
    N    matches 2-9
    [372] matches three or seven or two
    .    matches one or more character
    !    matches zero or more characters
Match a ten-digit phone number:
    _NXXNXXXXXX
Match an international number (from North America):
    _011.

See: https://wiki.asterisk.org/wiki/display/AST/Asterisk+Command+Reference

Asterisk CLI

(Remember tab completion!)

CLI> module reload chan_sip.so
CLI> dialplan reload
CLI> sip show peers
CLI> sip show peer twilio
CLI> sip show users
CLI> core show channels
CLI> core show channels verbose
CLI> core show channel PJSIP/111-00000024
CLI> channel request hangup PJSIP/111-00000024
CLI> module show
CLI> module reload app_voicemail.so
CLI> voicemail show users
CLI> module reload features
CLI> core restart now
CLI> core restart gracefully
CLI> core show uptime
CLI> logger mute
CLI> logger set level NOTICE off
CLI> core show hints

The sample configs below assume a branch office with four phones. All phones ring when a call comes in from outside, and everybody shares a common voicemail box. All phones are SIP phones, and outside connectivity comes from a SIP trunk provider (Twilio).

Debugging:

CLI> core set verbose 4
CLI> core set debug 4
CLI> sip set debug on

(If using pjsip: ‘pjsip set logger on’.)

Also, check listening ports with:

# netstat -panu

Furthermore, we can pass commands to asterisk from the shell, like:

# asterisk -x 'pjsip show endpoints' | grep 130
# watch "asterisk -x 'core show channels'"

Restarting:

/etc/asterisk/sip.conf

; /etc/asterisk/sip.conf
; See /etc/asterisk/sip.conf.dist for helpful comments.

[general]
context=unauthenticated
allowguest=no
udpbindaddr=0.0.0.0
tcpenable=no
tcpbindaddr=0.0.0.0
transport=udp
srvlookup=no
language=en
nat=force_rport,comedia
localnet=10.0.0.0/255.255.255.0
externaddr=nn.nnn.nn.nnn

[codecs](!)
disallow=all
allow=g722,ulaw

[twilio](!)
type=peer
context=incoming
username=AsteriskUser
secret=xxxxxxxxxxxxxxxxxx
insecure=port,invite
dtmfmode=auto
host=foo.pstn.us1.twilio.com

[phone](!,codecs)
type=friend
context=local
host=dynamic
dtmfmode=auto
rtp_symmetric=yes
rewrite_contact=yes
aggregate_mwi=yes
directmedia=nonat

[101](phone)
description=101 Polycom SoundPoint IP 335
secret=5Q0-#5th
mailbox=100@local

[102](phone)
description=102 Yealink T21 E2
secret=a137$a9tY
mailbox=100@local

[103](phone)
description=102 Yealink T21 E2
secret=a137$a9tY
mailbox=100@local

[103](phone)
description=102 Yealink T21 E2
secret=a137$a9tY
mailbox=100@local

/etc/asterisk/extensions.config

; /etc/asterisk/extensions.config
; See /etc/asterisk/extenstions.conf.dist for helpful comments.

[general]
static=yes
writeprotect=no
clearglobalvars=no

[globals]
MY_AREA_CODE=555
MY_NUMBER=15555555555
RING_TIME=25

[emergency]
exten => 911,1,Verbose(1,Call initiated to 911!)
    same => n,Dial(SIP/911)

[local]

include => emergency

include => parkedcalls

exten => welcome,1,Answer()
    same => n,Playback(enter-ext-of-person)
    same => n,WaitExten()

exten => 101,1,Dial(SIP/101,,tT)

exten => 102,1,Dial(SIP/102,,tT)

exten => 103,1,Dial(SIP/103,,tT)

exten => 104,1,Dial(SIP/104,,tT)

; *97 is arbitrary. We can set the "voicemail" button key mapping on the phones.
exten => *97,1,VoiceMailMain(100@local,s)

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

; Block toll numbers
exten => _900XXXXXXX,1,Hangup()
exten => _1900XXXXXXX,1,Hangup()
exten => _NXX976XXXX,1,Hangup()
exten => _1NXX976XXXX,1,Hangup()

; Block international
exten => _011.,1,Hangup()

exten => _1NXXNXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}")
    same => n,Dial(SIP/+${EXTEN}@twilio)

exten => _NXXNXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}")
    same => n,Dial(SIP/+1${EXTEN}@twilio)

exten => _NXXXXXX,1,Set(CALLERID(all)="+${MY_NUMBER}")
    same => n,Dial(SIP/+1${MY_AREA_CODE}${EXTEN}@twilio)

; Handle invalid entries:
exten => i,1,Playback(pbx-invalid)
    same => n,Goto(local,welcome,1)

; Handle time-outs
exten => t,1,Playback(vm-goodbye)
    same => n,Hangup()

[incoming]

exten => welcome,1,Answer()
    same => n,Background(/usr/share/asterisk/sounds/extra/enter-ext-of-person)
    same => n,WaitExten(8)
    same => n,Dial(allphones)

exten => _+X.,1,Goto(incoming,welcome,1)

exten => allphones,1,Dial(SIP/101&SIP/102&SIP/103&SIP/104,${RING_TIME},,tT)
    same => n,VoiceMail(100@local,u)

exten => 101,1,Dial(SIP/101,,tT)

exten => 102,1,Dial(SIP/102,,tT)

exten => 103,1,Dial(SIP/103,,tT)

exten => 104,1,Dial(SIP/104,,tT)

; Handle invalid entries
exten => i,1,Playback(pbx-invalid)
    same => n,Goto(incoming,welcome,1)

; Handle time-outs
exten => t,1,Playback(vm-goodbye)
    same => n,Hangup()

/etc/asterisk/voicemail.conf

; /etc/asterisk/voicemail.conf
; See /etc/asterisk/voicemail.conf.dist for detailed comments

[general]

format=wav49|gsm|wav
serveremail=asterisk
attach=no
maxmsg=100
maxsecs=300
minsecs=1
maxgreet=120
skipms=3000
maxsilence=7
silencethreshold=128
maxlogins=2
charset=UTF-8
tz=eastern
locale=en_US.utf8
callback=fromvm

[zonemessages]

eastern=America/New_York|'vm-received' Q 'digits/at' IMp 
central=America/Chicago|'vm-received' Q 'digits/at' IMp 
central24=America/Chicago|'vm-received' q 'digits/at' H N 'hours'
military=Zulu|'vm-received' q 'digits/at' H N 'hours' 'phonetic/z_p'
european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM

[local]

100 => 9931,My Mailbox,voicemail@example.com

## /etc/askterisk/features.conf ##

; /etc/askterisk/features.conf
; See /etc/askterisk/features.conf for helpful comments

[general]

courtesytone = beep
parkext => 700 
parkpos => 701-750
context => parkedcalls
parkingtime =>  90

PJSIP

PJSIP is the channel driver for asterisk that replaces the older chan_sip driver. Its config and concepts are slightly different. The file ‘sip.conf’ is replaced by ‘pjsip.conf’.

Unlike chan_sip, where everything is a channel, pjsip has a number of different conceptual objects.

Endpoint specifies core SIP options, and can link to Auth, AoR, and Transport sections. An endpoint requires at least one linked AoR section. Example:

[201]
type=endpoint
context=default
disallow=all
allow=ulaw
transport=simpletrans
auth=auth201
aors=201

AoR Address of Record links a Contact to an Endpoint. AoR objects can also set associations with mailboxes. Example:

[201]
type=aor
max_contacts=1

Contact holds info about inbound registrations, and aliases SIP URI’s. May be associated with an individual SIP user agent. Although they can be created manually, a contact is automatically created upon registration to an AoR. Example of manual contact in an AoR section:

[202]
type=aor
contact=sip:202@192.168.0.55:5060

Registration sets up outbound registration with another system (e.g. a local peer or provider’s trunk). Like an endpoint, a registration can also link to transport or auth sections. Example:

[mytrunk]
type=registration
transport=simpletrans
outbound_auth=mytrunk
server_uri=sip:myaccountname@203.0.113.200:5060
client_uri=sip:myaccountname@192.0.2.1:5060
retry_interval=60

Transport transport layer options, like tcp, udp, websockets, tls. Mulitple endpoints can share the same transport. Example:

[simpletrans]
type=transport
protocol=udp
bind=0.0.0.0

Auth holds inbound or outbound authentication options and credentials. Example

[auth201]
type=auth
auth_type=userpass
password=201
username=201

Identify controls how we identify from which endpoint a packet originates (by IP or by user). If we don’t define an Identify section, user identity is based on the packet’s SIP “From” header. Example:

[201]
type=identify
endpoint=201
match=203.0.113.200

Domain_Alias specifies an alias for a domain. Consulted if a session’s domain doesn’t match an AoR. (Not linked to other sections.)

ACL controls all inbound SIP. Can be defined in the ACL section, or in the acl.conf file. (Not linked to other sections.)

In our dialplan, we do:

exten => _2XX,1,Dial(PJSIP/${EXTEN})

instead of:

exten => _2XX,1,Dial(SIP/${EXTEN})

Some of the CLI commands differ with pjsip. For example:

CLI> pjsip show endpoints

instead of:

CLI> sip show peers

http://lists.digium.com/pipermail/asterisk-dev/2016-March/075422.html

The current Asterisk 13 and master git branches have a new feature that will be included in 13.8.0: The ability to compile and run Asterisk with a bundled version of pjproject All you have to do is add the “–with-pjproject-bundled” option to your ./configure command line and remove any other “–with-pjproject” option you may have specified.

Troubleshooting

CLI> core show channels
CLI> channel request hangup all
$ sudo watch "asterisk -x 'core show channels'"
$ sudo watch "asterisk -x 'core show channels verbose'"
$ sudo asterisk -rx 'core show channels concise'
$ sudo asterisk -rx 'core show channel PJSIP/xx_trunk-00000b8d'

RTCP may gather some call quality stats:

$ sudo asterisk -rx 'pjsip show channelstats'

Programming and Automation

CLI> channel originate PJSIP/126 application Playback hello-world

exten => 666,1,NoOp(-------- Voice Changer --------)
	same => n,Answer(1)
	same => n,Set(pranker=${CALLERID(all)})
	same => n,Set(PITCH_SHIFT(both)=lower)
	same => n,Read(prankee,enter-ext-of-person, 4)
	same => n,Log(NOTICE, ${pranker} pranked ${prankee} (voice change))
	same => n,Set(CALLERID(all)="April Furst" <667>)
	same => n,Dial(PJSIP/${prankee:0:3}, 20) 
	same => n,Voicemail(${prankee:0:3})
	same => n,Hangup()

exten => 664,1,NoOp(-------- Mysterious Numbers Station --------)
	same => n,Answer()
	same => n,Set(PITCH_SHIFT(tx)=lower)
	same => n,Set(i=0)
	same => n(while_start),While($[${i} < 64])
	same => n,Playback(silence/1)
	same => n,GotoIf($[${RAND(0,10)} < 8]?:letter)
	same => n,SayDigits(${RAND(0,9)})
	same => n,Goto(while_end)
	same => n(letter),SayPhonetic(${SHELL(echo ${RAND(0,6)} | tr 0-6 A-F)})
	same => n(while_end),Set(i=$[${i} + 1])
	same => n,EndWhile
	same => n,Playback(activated)
	same => n,Hangup()

One thing to note is that once we call the Dial() function, execution of the dialplan doesn’t continue until the function returns (i.e. one of the parties hangs up). If we want to do stuff during the call, use a macro with the “M()” option to Dial():

exten => 699,1,NoOp(-------- Test Dial() macros --------)
	same => n,Dial(PJSIP/+12485552222@my_trunk,20,M(mystery-call))

[macro-mystery-call]
exten => s,1,Wait(5)
	same => n,SayPhonetic(MYSTERY)
	same => n,Hangup()

If we’re dialing a local extension, do something like this instead:

exten => 699,1,NoOp(-------- Test Dial() macros --------)
	same => n,Dial(Local/123@my_context,20,M(mystery-call))

Debugging SIP

The signaling for a call between a SIP trunk and Asterisk server generally looks something like this:

A to B:  INVITE
B to A:  100 Trying
B to A:  180 Ringing
B to A:  180 Ringing
B to A:  200 OK
A to B:  ACK
...(RTP media packets flow but no SIP packets, even in a several-minute conversation)...
B to A:  BYE
A to B:  200 OK

The BYE packet often provides a Reason header, which can be helpful.

Additional (but similar) exchanges occur between the Asterisk server and phones.

A packet capture can help diagnose problems:

# tcpdump -i eth0 'host asterisk.example.com and port 5060' -vv -w 20170316-serverA-serverB-sip-port-5060.pcap

Call Parking

CLI> parking show default

A Note About DNS and SIP

If our DNS server supports NAPTR records (Amazon Route 53, Windows 2008 R2+ DNS, and NSD all do), it’s a good way to communicate server redundancy information to phones.

Asterisk: The Definitive Guide from O’Reilly is really good. Buy it if you’re running Asterisk.