feat: add asterisk pjsip integration
- infrastructure/docker/asterisk.Dockerfile: Asterisk 22.10.1 LTS compilado do fonte oficial (Debian trixie nao distribui mais o pacote asterisk), com PJSIP, AMI, ARI, res_odbc/res_config_odbc, cdr_adaptive_odbc, cel_odbc, app_queue - infrastructure/asterisk/config: templates renderizados no entrypoint (secrets via envsubst, nunca versionados) + sorcery.conf/extconfig.conf para PJSIP realtime, dialplan de teste (extensao 600) - infrastructure/postgres/init/002-asterisk-realtime.sql: tabelas ps_endpoints/ps_auths/ps_aors/ps_contacts/ps_endpoint_id_ips/ ps_registrations/cdr/cel no schema 'asterisk' - infrastructure/nftables: protege AMI/ARI/SIP contra acesso pela LAN (interface ens18), trazido da Fase 9 do TODO para ja, sem afetar SSH nem a rede interna do Docker - docker-compose.yml: servico asterisk em network_mode: host (RTP); Postgres publicado em 127.0.0.1:5432 (nao 0.0.0.0) para o Asterisk alcanca-lo, ja que host network nao enxerga a rede Docker interna Testado: AMI login, ARI com auth (401 sem auth), pjsip realtime consultando Postgres sem erro, dialplan originate -> CDR e CEL gravados corretamente, healthcheck do compose passando.
This commit is contained in:
236
infrastructure/postgres/init/002-asterisk-realtime.sql
Normal file
236
infrastructure/postgres/init/002-asterisk-realtime.sql
Normal file
@@ -0,0 +1,236 @@
|
||||
-- Tabelas de Realtime do Asterisk (PJSIP via res_config_odbc) + CDR/CEL
|
||||
-- (cdr_pgsql / cel_pgsql), todas no schema "asterisk" (nunca em "public",
|
||||
-- que é reservado ao domínio da aplicação — ver docs/ARCHITECTURE.md).
|
||||
--
|
||||
-- Colunas seguem o schema oficial documentado pelo Asterisk 22 para
|
||||
-- res_pjsip realtime (sorcery.conf + extconfig.conf apontam para estas
|
||||
-- tabelas). Caso uma coluna adicional seja necessária futuramente
|
||||
-- (ex.: campo específico de um módulo PJSIP menos comum), ela deve ser
|
||||
-- adicionada via migration, nunca editada manualmente em produção.
|
||||
|
||||
SET search_path TO asterisk, public;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_endpoints
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_endpoints (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
transport VARCHAR(255),
|
||||
aors VARCHAR(255),
|
||||
auth VARCHAR(255),
|
||||
context VARCHAR(255) DEFAULT 'default',
|
||||
disallow VARCHAR(255) DEFAULT 'all',
|
||||
allow VARCHAR(255),
|
||||
direct_media VARCHAR(3) DEFAULT 'yes',
|
||||
connected_line_method VARCHAR(255),
|
||||
direct_media_method VARCHAR(255),
|
||||
direct_media_glare_mitigation VARCHAR(255),
|
||||
disable_direct_media_on_nat VARCHAR(3),
|
||||
dtmf_mode VARCHAR(255) DEFAULT 'rfc4733',
|
||||
external_media_address VARCHAR(255),
|
||||
force_rport VARCHAR(3) DEFAULT 'yes',
|
||||
ice_support VARCHAR(3) DEFAULT 'no',
|
||||
identify_by VARCHAR(255) DEFAULT 'username,ip',
|
||||
mailboxes VARCHAR(255),
|
||||
moh_suggest VARCHAR(255) DEFAULT 'default',
|
||||
outbound_auth VARCHAR(255),
|
||||
outbound_proxy VARCHAR(255),
|
||||
rewrite_contact VARCHAR(3) DEFAULT 'yes',
|
||||
rtp_symmetric VARCHAR(3) DEFAULT 'yes',
|
||||
send_diversion VARCHAR(3),
|
||||
send_pai VARCHAR(3),
|
||||
send_rpid VARCHAR(3),
|
||||
timers VARCHAR(255) DEFAULT 'yes',
|
||||
timers_min_se INTEGER DEFAULT 90,
|
||||
timers_sess_expires INTEGER DEFAULT 1800,
|
||||
trust_id_inbound VARCHAR(3) DEFAULT 'no',
|
||||
trust_id_outbound VARCHAR(3) DEFAULT 'no',
|
||||
type VARCHAR(255) DEFAULT 'endpoint',
|
||||
use_avpf VARCHAR(3) DEFAULT 'no',
|
||||
use_ptime VARCHAR(3) DEFAULT 'no',
|
||||
callerid VARCHAR(255),
|
||||
callerid_privacy VARCHAR(255),
|
||||
callerid_tag VARCHAR(255),
|
||||
device_state_busy_at INTEGER DEFAULT 0,
|
||||
language VARCHAR(255) DEFAULT 'en',
|
||||
max_audio_streams INTEGER DEFAULT 1,
|
||||
max_video_streams INTEGER DEFAULT 1,
|
||||
media_encryption VARCHAR(255) DEFAULT 'no',
|
||||
media_use_received_transport VARCHAR(3) DEFAULT 'no',
|
||||
one_touch_recording VARCHAR(3) DEFAULT 'no',
|
||||
record_off_feature VARCHAR(255),
|
||||
record_on_feature VARCHAR(255),
|
||||
rtp_engine VARCHAR(255) DEFAULT 'asterisk',
|
||||
rtp_ipv6 VARCHAR(3) DEFAULT 'no',
|
||||
rtp_keepalive INTEGER,
|
||||
rtp_timeout INTEGER,
|
||||
rtp_timeout_hold INTEGER,
|
||||
sdp_owner VARCHAR(255),
|
||||
sdp_session VARCHAR(255),
|
||||
set_var TEXT,
|
||||
srtp_tag_32 VARCHAR(3) DEFAULT 'no',
|
||||
tone_zone VARCHAR(255),
|
||||
tos_audio VARCHAR(255),
|
||||
tos_video VARCHAR(255),
|
||||
cos_audio INTEGER,
|
||||
cos_video INTEGER,
|
||||
allow_transfer VARCHAR(3) DEFAULT 'yes',
|
||||
user_eq_phone VARCHAR(3) DEFAULT 'no',
|
||||
moh_passthrough VARCHAR(3) DEFAULT 'no',
|
||||
account_code VARCHAR(255),
|
||||
notify_early_inuse_ringing VARCHAR(3),
|
||||
max_contacts INTEGER DEFAULT 1,
|
||||
remove_existing VARCHAR(3) DEFAULT 'yes',
|
||||
voicemail_extension VARCHAR(255)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_ps_endpoints_id ON asterisk.ps_endpoints (id);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_auths
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_auths (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
auth_type VARCHAR(255) DEFAULT 'userpass',
|
||||
nonce_lifetime INTEGER DEFAULT 32,
|
||||
md5_cred VARCHAR(255),
|
||||
password VARCHAR(255),
|
||||
realm VARCHAR(255),
|
||||
username VARCHAR(255)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_aors
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_aors (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
contact VARCHAR(255),
|
||||
default_expiration INTEGER DEFAULT 3600,
|
||||
mailboxes VARCHAR(255),
|
||||
max_contacts INTEGER DEFAULT 1,
|
||||
minimum_expiration INTEGER DEFAULT 60,
|
||||
remove_existing VARCHAR(3) DEFAULT 'yes',
|
||||
qualify_frequency INTEGER DEFAULT 0,
|
||||
authenticate_qualify VARCHAR(3) DEFAULT 'no',
|
||||
max_expiration INTEGER DEFAULT 7200,
|
||||
outbound_proxy VARCHAR(255),
|
||||
support_path VARCHAR(3) DEFAULT 'no',
|
||||
qualify_timeout NUMERIC(5,3) DEFAULT 3.0,
|
||||
voicemail_extension VARCHAR(255),
|
||||
remove_unavailable VARCHAR(3) DEFAULT 'no'
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_contacts (populada dinamicamente pelo registro dos ramais)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_contacts (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
uri VARCHAR(511),
|
||||
expiration_time BIGINT,
|
||||
qualify_frequency INTEGER DEFAULT 0,
|
||||
outbound_proxy VARCHAR(255),
|
||||
path TEXT,
|
||||
user_agent VARCHAR(255),
|
||||
qualify_timeout NUMERIC(5,3) DEFAULT 3.0,
|
||||
reg_server VARCHAR(255),
|
||||
authenticate_qualify VARCHAR(3) DEFAULT 'no',
|
||||
via_addr VARCHAR(255),
|
||||
via_port INTEGER,
|
||||
call_id VARCHAR(255),
|
||||
endpoint VARCHAR(255),
|
||||
prune_on_boot VARCHAR(3) DEFAULT 'no'
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_ps_contacts_endpoint ON asterisk.ps_contacts (endpoint);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_endpoint_id_ips (identificação de troncos por IP)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_endpoint_id_ips (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
endpoint VARCHAR(255),
|
||||
match VARCHAR(80),
|
||||
srv_lookups VARCHAR(3) DEFAULT 'yes',
|
||||
match_header VARCHAR(255)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_ps_endpoint_id_ips_endpoint ON asterisk.ps_endpoint_id_ips (endpoint);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- ps_registrations (troncos com registration outbound)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.ps_registrations (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
auth_rejection_permanent VARCHAR(3) DEFAULT 'yes',
|
||||
client_uri VARCHAR(255),
|
||||
contact_user VARCHAR(255),
|
||||
expiration INTEGER DEFAULT 3600,
|
||||
max_retries INTEGER DEFAULT 10,
|
||||
outbound_auth VARCHAR(255),
|
||||
outbound_proxy VARCHAR(255),
|
||||
retry_interval INTEGER DEFAULT 60,
|
||||
forbidden_retry_interval INTEGER DEFAULT 0,
|
||||
server_uri VARCHAR(255),
|
||||
transport VARCHAR(255),
|
||||
support_path VARCHAR(3) DEFAULT 'no',
|
||||
fatal_retry_interval INTEGER DEFAULT 0,
|
||||
line VARCHAR(3) DEFAULT 'no',
|
||||
endpoint VARCHAR(255)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- CDR (cdr_pgsql) — colunas padrão do CDR nativo do Asterisk
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.cdr (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
accountcode VARCHAR(20),
|
||||
src VARCHAR(80),
|
||||
dst VARCHAR(80),
|
||||
dcontext VARCHAR(80),
|
||||
clid VARCHAR(80),
|
||||
channel VARCHAR(80),
|
||||
dstchannel VARCHAR(80),
|
||||
lastapp VARCHAR(80),
|
||||
lastdata VARCHAR(80),
|
||||
start TIMESTAMP,
|
||||
answer TIMESTAMP,
|
||||
end_time TIMESTAMP,
|
||||
duration INTEGER,
|
||||
billsec INTEGER,
|
||||
disposition VARCHAR(45),
|
||||
amaflags VARCHAR(45),
|
||||
uniqueid VARCHAR(150),
|
||||
userfield VARCHAR(255),
|
||||
linkedid VARCHAR(150),
|
||||
peeraccount VARCHAR(20),
|
||||
sequence INTEGER
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_uniqueid ON asterisk.cdr (uniqueid);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_linkedid ON asterisk.cdr (linkedid);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_start ON asterisk.cdr (start);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- CEL (cel_pgsql)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS asterisk.cel (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
eventtype VARCHAR(30),
|
||||
eventtime TIMESTAMP,
|
||||
userdeftype VARCHAR(255),
|
||||
cid_name VARCHAR(80),
|
||||
cid_num VARCHAR(80),
|
||||
cid_ani VARCHAR(80),
|
||||
cid_rdnis VARCHAR(80),
|
||||
cid_dnid VARCHAR(80),
|
||||
exten VARCHAR(80),
|
||||
context VARCHAR(80),
|
||||
channame VARCHAR(80),
|
||||
appname VARCHAR(80),
|
||||
appdata VARCHAR(512),
|
||||
accountcode VARCHAR(20),
|
||||
uniqueid VARCHAR(150),
|
||||
linkedid VARCHAR(150),
|
||||
peer VARCHAR(80),
|
||||
userfield VARCHAR(255),
|
||||
extra TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_uniqueid ON asterisk.cel (uniqueid);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_linkedid ON asterisk.cel (linkedid);
|
||||
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_eventtime ON asterisk.cel (eventtime);
|
||||
Reference in New Issue
Block a user