Aller au contenu

PJSIP — la triade Endpoint / AOR / Auth

Asterisk a remplacé chan_sip (legacy) par chan_pjsip depuis la version 13. PJSIP est plus modulaire, plus sécurisé, mais déroute au début parce qu'un seul téléphone = 3 objets de configuration. Une fois le pourquoi compris, c'est limpide.

Le concept

Pour un téléphone IP qui se connecte, PJSIP demande de définir 3 entités distinctes :

       ┌─────────────┐
       │  Endpoint   │  ← logique métier : codecs, contexte, NAT, ...
       │  "1001"     │
       └──────┬──────┘
              │ aors=
       ┌─────────────┐
       │     AOR     │  ← localisation : où joindre cet endpoint
       │   "1001"    │     (max_contacts, qualify, registration)
       └──────┬──────┘
              │ auth=
       ┌─────────────┐
       │   Auth      │  ← creds : username + password (ou cert)
       │  "1001"     │
       └─────────────┘

Pourquoi cette séparation ? Parce qu'on peut imaginer :

  • Un endpoint (logique : "le poste de Jean") avec plusieurs AORs (Jean a 3 téléphones différents qui s'enregistrent).
  • Plusieurs endpoints qui partagent le même Auth (un trunk partage ses creds avec plusieurs flux).
  • Un endpoint sans AOR (pour un endpoint outbound-only).
  • Un endpoint sans Auth (pour un peering IP-trust sans password).

Cette flexibilité paye en architecture quand on configure des cas complexes (multi-device, hot-desking, trunks redondants).

Endpoint — la "personne" SIP

L'endpoint définit comment Asterisk traite l'utilisateur une fois identifié. C'est ici qu'on configure :

  • Codecs autorisés (allow=, disallow=)
  • Contexte du dialplan d'arrivée (context=)
  • NAT settings (rtp_symmetric, force_rport, rewrite_contact)
  • Direct media (direct_media=yes/no — bypass Asterisk pour le RTP)
  • Mailbox associée
  • Caller ID
  • DTMF mode (rfc4733, inband, info)
  • Trustables (trust_id_inbound, trust_id_outbound)

Exemple minimal :

[1001]
type = endpoint
context = from-internal
disallow = all
allow = ulaw,alaw,g722
auth = 1001
aors = 1001
direct_media = no
rtp_symmetric = yes
force_rport = yes
rewrite_contact = yes

AOR — Address Of Record

L'AOR (RFC 3261) est où on joint un endpoint. C'est-à-dire les adresses IP/port où des Contact sont enregistrés.

Pour un téléphone qui s'enregistre via REGISTER :

[1001]
type = aor
max_contacts = 1               # un seul téléphone à la fois
qualify_frequency = 60         # OPTIONS toutes les 60s
remove_existing = yes          # remplace l'ancien Contact à chaque REGISTER

Pour un peering statique (trunk SIP par ex) :

[trunk-sewan]
type = aor
contact = sip:trunkfsc1.sewan.fr:5070
qualify_frequency = 60

max_contacts > 1 permet multi-device : un même utilisateur a plusieurs téléphones (bureau + softphone + DECT) qui s'enregistrent sous la même AOR. Les appels sonnent sur tous simultanément (forking).

Auth — les credentials

[1001]
type = auth
auth_type = userpass
username = 1001
password = SuperSecretRandom32CharsHere

Pour un trunk avec digest auth (Sewan typique) :

[trunk-sewan-auth]
type = auth
auth_type = userpass
username = ttrunk-2815ba
password = Zgak6vYrPSO9
realm = technotrement3.sewan.eu

Les liens entre les 3

Dans l'endpoint : - aors= pointe vers une AOR (peut être plusieurs séparées par virgule) - auth= pointe vers une Auth (utilisée pour authentifier les requêtes entrantes, ex: REGISTER d'un téléphone) - outbound_auth= pointe vers une Auth (pour les requêtes sortantes, ex: register vers un trunk distant)

[1001]
type = endpoint
auth = 1001        ; quand quelqu'un se présente comme 1001, vérifier avec [1001]
aors = 1001        ; quand on veut joindre 1001, regarder dans AOR [1001]

Identify — l'autre voie d'identification

Quand un trunk s'authentifie par IP plutôt que par digest, on ajoute un identify :

[trunk-sewan-identify]
type = identify
endpoint = trunk-sewan       ; si l'INVITE vient des IPs ci-dessous, c'est ce trunk
match = 178.255.160.141
match = trunkfsc1.sewan.fr   ; FQDN résolu au boot

Sans identify, un INVITE entrant non authentifié se mappe sur l'endpoint anonymous (s'il existe) — généralement bloqué pour éviter le toll fraud.

Registration — pour s'enregistrer chez un trunk

Symétrique : quand notre Asterisk est client d'un trunk distant et doit s'enregistrer auprès :

[trunk-sewan-reg]
type = registration
outbound_auth = trunk-sewan-auth
server_uri = sip:trunkfsc1.sewan.fr:5070
client_uri = sip:ttrunk-2815ba@technotrement3.sewan.eu:5070
expiration = 600                ; renew chaque 10 min

Comment FreePBX cache cette complexité

FreePBX stocke tout en base MariaDB et génère ces fichiers de conf : - /etc/asterisk/pjsip.endpoint.conf - /etc/asterisk/pjsip.aor.conf - /etc/asterisk/pjsip.auth.conf - /etc/asterisk/pjsip.transports.conf - /etc/asterisk/pjsip.registration.conf - /etc/asterisk/pjsip.identify.conf

Plus les _custom.conf correspondants pour les overrides utilisateur.

Quand on crée une "Extension" via l'UI FreePBX, il génère automatiquement l'endpoint + AOR + Auth associés. Quand on crée un "Trunk", idem. C'est pour ça que la doc d'Asterisk pure semble "plus compliquée" que FreePBX — c'est parce que FreePBX écrit la triade pour vous.

Diagnostic typique

Problème Commande
L'extension ne s'enregistre pas pjsip show endpoint 1001 puis vérifier [Auth] rules
Pas joignable par appel pjsip show aor 1001 → contacts vides ?
Le trunk ne register pas pjsip show registrations puis vérifier auth + serveur
INVITE entrant rejeté pjsip show identifies → IP source bien matchée ?

Où chercher les configs FreePBX-générées

/etc/asterisk/pjsip.endpoint.conf       # généré, ne pas éditer
/etc/asterisk/pjsip.endpoint_custom.conf # vos overrides
/etc/asterisk/pjsip.endpoint_custom_post.conf  # post hooks

Convention FreePBX : jamais toucher les *.conf sans suffixe (générés). Ne modifier que les _custom.conf.

Suivant : Transports PJSIP