Freedom Internet PjSip
This Asterisk setup uses chan_pjsip / pjsip.conf instead of chan_sip /
sip.conf.
Replace all the RED stuff by the
appropriate values!
If you are not a Freedom internet
or VoIPGRID customer, you have to replace the
GREEN stuff as well.
And the BLUE stuff is about
selecting transports.
Note: This setup is for PjSip without NAT! You can use PjSip with NAT
though. See:
Configuring
res_pjsip to work through NAT
General
A major difference with sip.conf is that you can set far less defaults.
A lot of general settings from sip.conf now have to be set on a per
telephone basis.
The example below just sets the default realm;
[global]
type=global
;debug=yes
; From domain
default_realm=My_Domain
Furthermore, a lot of config statements have slightly different names.
Below some of the differences.
Note: The meaning in sip.conf vs psjip.conf is not always perfectly
identical!
sip.conf | pjsip.conf |
---|---|
allowoverlap | allow_overlap |
bindaddr | bind (See: Transports) |
contactdeny | contact_deny |
contactpermit | contact_permit |
defaultuser | username |
directmedia | direct_media |
dtlsverify | dtls_verify |
dtmfmode | dtmf_mode |
fromdomain | from_domain |
fromuser | from_user |
sendrpid | send_rpid |
sipdebug | debug |
srvlookup | srv_lookups |
tlscertfile | cert_file |
tlsdontverifyserver=yes | verify_server=no |
tlsprivatekey | priv_key_file |
trustrpid | trust_id_inbound |
More in the Python script 'sip_to_pjsip.py', which is part of the Asterisk
source.
Note: There is no real equivalent of 'allowguest=yes'. There is however
something pretty close at the bottom of this page.
The way registrations are stored in '/var/lib/asterisk/astdb.sqlite3' is also different. So, when you move from Sip to PjSip you need to re-register your telephones!
And you need to modify extensions.conf before you can dial!
Transports
There is a bit of a quirk here. When setting 'bind=[::]', older versions of
PjSip will use
IPv4-mapped
IPv6 addresses. So instead of '10.20.30.40' it might use
'::ffff:10.20.30.40'.
All that needs to be done to fix this, is to move the pointer seven bytes to
the right;
::ffff:10.20.30.40 ↓ ↑ └───→──┘
This requires two lines of code. One to test if the address 'starts' with '::ffff:'. A second to move the pointer if it does.
PjSip on the other hand, doesn't do this. Instead, newer versions use
IPv6-only sockets along side IPv4 sockets. This means that with newer
versions you can use 'bind=[::]' in combination with 'bind=0.0.0.0'!
The example below can be used to test for IPv6-only sockets;
[transport-tcp6] type=transport allow_reload=yes protocol=tcp bind=[::]
After a reload check this with netstat;
~$ netstat -an | grep "5060" tcp6 0 0 :::5060 :::* LISTEN
Note that both IPv6-only and dual stack sockets show up as IPv6!
Next, try to telnet to '127.0.0.1 5060'. If this doesn't work, the IPv6 sockets are IPv6-only, and you can safely use 'bind=[::]' alongside 'bind=0.0.0.0'!
The example below uses the IPv6 address of the Ethernet interface
('2001:db8:1234:1::1') for IPv6 and any interface ('0.0.0.0') for IPv4.
This will work with older versions of PjSip.
For older versions, replace '2001:db8:1234:1::1' by your IPv6 address.
For 'newer' versions (since 2017) use 'bind=[::]' instead of
'bind=[2001:db8:1234:1::1]'.
; --- UDP --- ; Default transport [transport-udp6] type=transport allow_reload=yes protocol=udp ;bind=[2001:db8:1234:1::1] ; Old bind=[::] ; 1st fallback [transport-udp] type=transport allow_reload=yes protocol=udp bind=0.0.0.0 ; --- TCP --- [transport-tcp6] type=transport allow_reload=yes protocol=tcp ;bind=[2001:db8:1234:1::1] ; Old bind=[::] [transport-tcp] type=transport allow_reload=yes protocol=tcp bind=0.0.0.0 ; --- TLS --- [transport-tls6] type=transport allow_reload=yes protocol=tls ;bind=[2001:db8:1234:1::1] ; Old bind=[::] cert_file=/etc/asterisk/fullchain.pem priv_key_file=/etc/asterisk/privkey.pem ca_list_path=/etc/ssl/certs ;verify_client=no ;verify_server=no ;require_client_cert=no allow_wildcard_certs=yes ;dtls_verify=no method=sslv23 ;method=tlsv1_2 ;method=tlsv1 [transport-tls] type=transport allow_reload=yes protocol=tls bind=0.0.0.0 cert_file=/etc/asterisk/fullchain.pem priv_key_file=/etc/asterisk/privkey.pem ca_list_path=/etc/ssl/certs ;verify_client=no ;verify_server=no ;require_client_cert=no allow_wildcard_certs=yes ;dtls_verify=no method=sslv23 ;method=tlsv1_2 ;method=tlsv1
The certs are generated with
Dehydrated.
The TLS method ('method=') may depend on your software version and the TLS
version used by your VoIP service provider /
ITSP (Internet Telephony Service Provider).
Note: Without a 'verify_server=no' TLS will fail if your ITSP uses a
self-signed cert.
Note: A wildcard cert for '*.example.org' allows 'foo.example.org',
not 'foo.bar.example.org'.
After a reload, this should show up in netstat.
A 'bind=[2001:db8:1234:1::1]' shows up as;
~$ netstat -an | egrep "506[01]" tcp 0 0 0.0.0.0:5060 :::* LISTEN tcp 0 0 0.0.0.0:5061 :::* LISTEN tcp6 0 0 2001:db8:1234:1::1:5060 :::* LISTEN tcp6 0 0 2001:db8:1234:1::1:5061 :::* LISTEN udp 0 0 0.0.0.0:5060 :::* udp6 0 0 2001:db8:1234:1::1:5060 :::*
A 'bind=[::]', on the other hand, shows up as;
tcp 0 0 0.0.0.0:5060 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:5061 0.0.0.0:* LISTEN tcp6 0 0 :::5060 :::* LISTEN tcp6 0 0 :::5061 :::* LISTEN udp 0 0 0.0.0.0:5060 0.0.0.0:* udp6 0 0 :::5060 :::*
This is similar to a 'sip.conf' with 'bindaddr=::', 'tcpenable=yes' and
'tlsenable=yes': Fully dual stack on all interfaces.
Below an 'asterisk -rx "pjsip show transports"';
Transport: transport-tcp tcp 0 0 0.0.0.0:5060 Transport: transport-tcp6 tcp 0 0 [::]:5060 Transport: transport-tls tls 0 0 0.0.0.0:5061 Transport: transport-tls6 tls 0 0 [::]:5061 Transport: transport-udp udp 0 0 0.0.0.0:5060 Transport: transport-udp6 udp 0 0 [::]:5060
Transport selection
For remote registration PjSip will look for NAPTR, SRV, AAAA (IPv6 address) and A (IPv4 address) DNS records in that order. When SRV records are available it prefers TLS over TCP and TCP over UDP;
-
NAPTR
Any SIP addresses found here will be processed as below. -
SRV
-
TLS
- AAAA
- A
-
TCP
- AAAA
- A
-
UDP
- AAAA
- A
-
TLS
- AAAA
- A
Without SRV records it uses the order set in pjsip.conf.
If you want something else you have to set the
transport in the
registration and
endpoint sections.
Fail over
With res_sip and IAX, Asterisk just uses the 'first' host or IP address it
finds; If an IP address fails, it won't try any other hosts or IP
addresses.
With PjSip, if a host times out, it will try the next host or IP address.
So PjSip makes full use of any redundancy your ITSP might provide.
Note: For an IPv6 to IPv4 fail over, you need to specify a transport in a
non IP version specific way
(see ITSP Transport below) or no transport at all.
Personally, I don't think you need an IPv6 to IPv4 fail over. Unless of
course, if your ITSP sends you an invite via IPv4 after registering using
IPv6.
Telephones on LAN
A telephone called 'My_phone' with password 'Pass_Word' in 'My_Domain',
with context 'lan-phones'.
Config sections are 'aor', 'auth' and 'endpoint'
Telephone AoR
AoR means Address-of-Record. This in fact the SIP URI of the telephone. In
this case this established by the telephone registering to your Asterisk.
Hence the 'auth' section.
'max_contacts' limits the number of telephones that can be simultaneously
registered with the same username. In this case one;
; --- My_Phone ---
[my_phone]
type=aor
max_contacts=1
Telephone Auth
[my_phone] type=auth realm=My_Domain username=My_Phone password=Pass_Word
Telephone Endpoint
Endpoint describes the properties of the telephone;
[my_phone] type=endpoint context=lan-phones dtmf_mode=auto disallow=all allow=alaw ;allow=ulaw direct_media=no from_domain=My_Domain contact_deny=0.0.0.0/0 contact_deny=::/0 contact_permit=192.168.0.0/16 contact_permit=2001:db8:1234::/48 auth=my_phone aors=my_phone
'direct_media=no' keeps Asterisk in the RTP audio path, turning it into a IPv6 <-> IPv4 proxy.
It's probably a good idea to test your telephones before configuring your
ITSP.
Note: You need to re-register your telephones when moving from Sip to PjSip!
And you need to modify extensions.conf before you
can dial!
Below the result of a 'pjsip show endpoints';
Endpoint: my_phone Not in use 0 of inf InAuth: my_phone/my_phone Aor: my_phone 1 Contact: my_phone/sip:my_phone@192.168.7.9:5060 Hash NonQual nan
If a telephone is not registered, it says 'Unavailable' instead of 'Not in use'.
Remote registrations
A remote registration with account-id / user-name 'Account_Id' and password
'Pass_Word'.
This has additional sections 'registration' and
'identify'.
Note: Your ITSP 'translates' your telephone number to your account-id /
user-name. SIP on the other hand, deals with things like user-names and
domains! So telephone numbers have a limited meaning.
ITSP Registration
; --- Registration --- [freedom] type=registration retry_interval=20 max_retries=20000 contact_user=Telephone_Number auth_rejection_permanent=no expiration=120 ;transport=transport-udp ;transport=transport-udp6 ;transport=transport-tls6 outbound_auth=freedom client_uri=sip:Account_Id@sipproxy.voipgrid.nl ;client_uri=sip:Account_Id@sip6.voipgrid.nl server_uri=sip:sipproxy.voipgrid.nl ;server_uri=sip:sip6.voipgrid.nl line=yes endpoint=freedom
Note: If an endpoint is specified, Asterisk insists on 'line=yes' and vice versa!
- 'server_uri' is used in the 'REGISTER' header line of the REGISTER.
- 'client_uri' is used in the 'To:' and 'From:' header lines of the REGISTER.
-
'contact_user' sets the 'Contact:' header.
When the 'contact_user' is not set, it defaults to 's' (Start). Some examples set 'contact_user' to 'Account_Id' instead of 'Telephone_Number'. Other values are also used.
Note: A SIP URI requires less escaping than a HTTP URI. For instance, '+31207654321' is a valid 'contact_user' 'Telephone_Number'.
Note: Using '_uri:sips:' instead of '_uri:sip:' may not work: If you
can't make Asterisk use 'sips:' in outgoing 'INVITE' 'From:' headers as
well, the remote server will reject INVITEs.
Below an registration example (uses sip6 instead of sipproxy);
REGISTER sip:sip6.voipgrid.nl SIP/2.0 Via: SIP/2.0/UDP [2001:db8:1234:1::1]:5060;rport;branch=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX From: <sip:Account_Id@sip6.voipgrid.nl>;tag=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX To: <sip:Account_Id@sip6.voipgrid.nl> Call-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX CSeq: XXXXX REGISTER Contact: <sip:Telephone_Number@[2001:db8:1234:1::1]:5060> Expires: 120 Allow: OPTIONS, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, MESSAGE, REFER Max-Forwards: 70 User-Agent: Asterisk PBX Version Authorization: Digest username="Account_Id", realm="voipgrid.nl", nonce="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", uri="sip:Account_Id@sip6.voipgrid.nl", response="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" Content-Length: 0
ITSP Transport
You might want to set the
transport.
If you do, make sure the selected protocol and IP version are supported by
the remote end!
You can set a transport by a line 'transport=Some_Transport'. For instance,
'transport=transport-udp6'. This however, is IP version specific!
For a non IP version specific transport selection, append the transport
to the SIP URI instead. The example below sets the transport to UDP;
server_uri=sip:sipproxy.voipgrid.nl\;transport=udp client_uri=sip:Account_Id@sipproxy.voipgrid.nl\;transport=udp
This way you can have an IPv6 to IPv4 fail over, IF your ITSP supports it.
Line
'line=yes' adds a 'line=Some_String' to the 'Contact:' header line;
Contact: <sip:Telephone_Number@[2001:db8:1234:1::1]:5060;line=XXXXXXX>
This will put the same string in incoming 'INVITE' or 'To:' lines;
INVITE sip:Account_Id@[2001:db8:1234:1::1]:5060;line=XXXXXXX SIP/2.0
If for some reason the 'match' (see
the identify section below) doesn't work,
the match is made on the 'line' string.
Note: If an endpoint is specified, Asterisk insists on 'line=yes' and
vice versa!
ITSP Auth
[freedom] type=auth ;auth_type=userpass realm=voipgrid.nl username=Account_Id password=Pass_Word
ITSP AoR
Here the AoR is a SIP URI;
; --- Endpoint --- [freedom] type=aor contact=sip:sipproxy.voipgrid.nl ;contact=sip:sip6.voipgrid.nl
Some examples use 'contact=sip:Accout_Id@sipproxy.voipgrid.nl' instead.
If you you don't want to set a transport in the Endpoint section, you can
set it here instead. The example below sets the transport to UDP;
contact=sip:sipproxy.voipgrid.nl\;transport=udp
ITSP Identify
This identifies incoming requests.
[freedom] type=identify endpoint=freedom ; Match voipgrid.nl ;match=185.103.76.0/22,195.35.114.0/23,2a06:2a80::/29 match=185.103.76.0/22 match=195.35.114.0/23 match=2a06:2a80::/29
Both a single-line and multi-line 'match' work.
ITSP Endpoint
[freedom] type=endpoint context=freedom-in dtmf_mode=auto disallow=all allow=alaw direct_media=no trust_id_inbound=yes send_rpid=yes ;transport=transport-udp ;transport=transport-udp6 ;transport=transport-tls6 from_user=Account_Id from_domain=voipgrid.nl outbound_auth=freedom aors=freedom ;rtp_ipv6=yes ; SRTP ;media_encryption_optimistic=yes ;media_encryption=sdes
Note: SRTP / media_encryption needs to be enabled at the remote end for incoming audio encryption to work!
'from_domain' sets the domain in the 'From:' header line in INVITE.
Some examples use 'from_domain=sipproxy.voipgrid.nl' instead of
'from_domain=voipgrid.nl'. Which results in
'Account_Id@sipproxy.voipgrid.nl' instead of 'Account_Id@voipgrid.nl'
Below an outgoing INVITE example (uses sip6 instead of sipproxy);
INVITE sip:Dialled_Number@sip6.voipgrid.nl SIP/2.0 Via: SIP/2.0/UDP [2001:db8:1234:1::1]:5060;branch=XXXXXXXXXXXXXXX Max-Forwards: 70 From: "Display-Name" <sip:Account_Id@voipgrid.nl>;tag=XXXXXXXXXX To: <sip:Dialled_Number@sip6.voipgrid.nl> Contact: <sip:Account_Id@[2001:db8:1234:1::1]:5060> Call-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@voipgrid.nl CSeq: 102 INVITE User-Agent: Asterisk PBX Version Date: Thu, 07 Nov 2024 14:55:46 GMT Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE Supported: replaces, timer Remote-Party-ID: "Display-Name" <sip:Telephone_Number@voipgrid.nl>;party=calling;privacy=off;screen=no Content-Type: application/sdp Content-Length: 279
When you don't set an endpoint transport, the default transport will be
used for outgoing requests (such as outgoing INVITEs).
Note: Your ITSP may use a different transport for requests send to you
(such as incoming INVITEs), than you configured for outgoing requests!
They may use the transport you registered with instead. So if you
configured a transport for registration, it's probably a good idea to
configure the same transport for endpoint as well.
You can select a transport by a line 'transport=Some_Transport', or append
a transport to the SIP URI in the AoR section.
extensions.conf
Use 'PJSIP' instead of 'SIP' in dial commands.
E.G.:
exten => 1234,1,Dial(PJSIP/Some_Extention,60,t) same => n,Hangup()
Rasterisk output
Check things with rasterisk.
Endpoints
Below the result of a 'pjsip show endpoints' (uses 'sip6.voipgrid.nl' and transport 'transport-tls6');
Endpoint: freedom Not in use 0 of inf OutAuth: freedom/Account_Id Aor: freedom 0 Contact: freedom/sip:sip6.voipgrid.nl Hash NonQual nan Transport: transport-tls6 tls 0 0 [::]:5061 Identify: freedom/freedom Match: 185.103.76.0/22 Match: 195.35.114.0/23 Match: 2a06:2a80::/29
Registrations
Below the result of a 'pjsip show registrations';
freedom/sip:sip6.voipgrid.nl freedom Registered (exp. 102s)
Invite
An example incoming INVITE;
INVITE sip:Account_Id@[2001:db8:1234:1::1]:5060;line=XXXXXXX SIP/2.0 Record-Route: <sip:[2A06:2A80:0:114:0:0:0:41]:6060;r2=on;lr> Record-Route: <sip:195.35.114.41:5070;r2=on;lr> Record-Route: <sip:195.35.114.57;lr;ftag=XXXXXXXXXXXX;did=XXXXXXXXXXXX;mc=from-dutch;cc=XXXXXXXXXX> Via: SIP/2.0/UDP [2A06:2A80:0:114:0:0:0:41]:6060;branch=XXXXXXXXXXXXXXXXXXXXXX Via: SIP/2.0/UDP 195.35.114.57:5060;branch=XXXXXXXXXXXXXXXXXXXXXX Via: SIP/2.0/UDP 195.35.114.107:5060;received=195.35.114.107;rport=5060;branch=XXXXXXXXXXXXXXXXXXXXX From: "Display-Name" <sip:Telephone_Number@voipgrid.nl>;tag=XXXXXXXXXXXX To: <sip:Account_Id@voipgrid.nl> Contact: <sip:Telephone_Number@195.35.114.107:5060> Call-ID: XXXXXXXXXXXX CSeq: 28282 INVITE Allow: OPTIONS, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, INFO, REFER Supported: 100rel, timer, replaces, norefersub Session-Expires: 1800 Min-SE: 90 Max-Forwards: 68 User-Agent: VGUA Content-Type: application/sdp Content-Length: 357
Outgoing and incoming INVITEs compared;
Header line |
Outgoing | Incoming |
---|---|---|
INVITE | Dialled Telephone Number |
Account Id / User Name |
From: | Account Id / User Name |
Caller's Telephone Number |
To: | Dialled Telephone Number |
Account Id / User Name |
Contact: | Account Id / User Name |
Caller's Telephone Number |
Note: Your ITSP may alter the caller's telephone number in incoming
INVITEs;
In the 'From:' line my ITSP uses
'trunk_prefix area_code subscribers_number' for national calls and
'international_call_prefix country_code area_code subscribers_number'
for international calls. This is the number displayed on your telephone.
In the 'Contact:' line it's
'+ country_code area_code subscribers_number'.
National From: |
International From: |
Contact: |
---|---|---|
0207654321 | 0031207654321 | +31207654321 |
Note: In this example the trunk prefix is '0' and the international call prefix is '00'. These vary by country. See: Country calling codes
Hairpin
Below the result of a 'pjsip show endpoints' during dialling myself (uses 'sip6.voipgrid.nl' and transport 'transport-udp6');
Endpoint: freedom In use 2 of inf OutAuth: freedom/Account_Id Aor: freedom 0 Contact: freedom/sip:sip6.voipgrid.nl Hash NonQual nan Transport: transport-udp6 udp 0 0 [::]:5060 Identify: freedom/freedom Match: 185.103.76.0/22 Match: 195.35.114.0/23 Match: 2a06:2a80::/29 Channel: PJSIP/freedom-XXXXXXXX/AppDial Up 00:00:08 Exten: CLCID: "My_Display-Name" <My_Telephone_Number> Channel: PJSIP/freedom-XXXXXXXX/Dial Up 00:00:08 Exten: Account_Id CLCID: "" <Account_Id>
The first 'Channel' (AppDial) is outgoing, the second (Dial) incoming.
'Exten' is the dialled extension in incoming calls.
My ITSP tries to find the name that goes with the calling telephone number
and, if found, makes this the Diplay-Name in the 'From:' header in the
incoming INVITE. Asterisk then copies this to the INVITE send to my
telephones. Which in turn, display the name;
Endpoint: my_phone In use 1 of inf InAuth: my_phone/my_phone Aor: my_phone 1 Contact: my_phone/sip:my_phone@192.168.7.9:5060 Hash NonQual nan Channel: PJSIP/my_phone-XXXXXXXX/AppDial Up 00:00:10 Exten: CLCID: "Display-Name" <Telephone_Number>
Use IPv6 instead of IPv4
If you ever find yourself behind a dual stack WAN link with
CGN for IPv4,
IPv6 is probably the only thing that works.
If you are a Freedom Internet or VoIPGRID customer and you prefer to use
IPv6 over IPv4 for your remote registration, configure 'sip6.voipgrid.nl'
instead of 'sipproxy.voipgrid.nl'. This will default to TCP.
If you prefer UDP to TCP, set the transport to 'transport-udp6'.
And if you prefer TLS, set the transport to 'transport-tls6'. This
will connect to port 5061.
Match on header
This is about as close to 'allowguest=yes' as you can get. Probably not
something you want, but if you do here it is.
This allows anyone who makes it past the firewall to access you with
an INVITE containing: 'To: <sip:Me@My_Domain.Tld>';
In pjsip.conf:
[me] type=aor contact=sip:Me@My_Domain.Tld [me] type=identify endpoint=me match_header=To: /\<Me@My_Domain\.Tld\>/
Note that this is fact a regex. Somehow a regular match doesn't work.
[me] type=endpoint context=me-in disallow=all allow=alaw allow=ulaw allow=g722 aors=me
In extensions.conf:
[me-in] exten => Me,1,Dial(PJSIP/Some_Extention,60,t) same => n,Hangup()