; --------------------------------------------------------------------------- ; Hold Slayer lab — PJSIP configuration ; --------------------------------------------------------------------------- ; SECURITY: this endpoint answers calls. Asterisk's stock examples allow ; anonymous inbound, which is a well-known toll-fraud target. This config ; refuses it: every call must authenticate as the `hold-slayer` endpoint. ; ; There is no PSTN behind this Asterisk — an unauthorised call reaches only ; the lab dialplan and costs nothing. The lock-down is defence in depth and ; so this config is never copied somewhere it would matter. ; --------------------------------------------------------------------------- [global] type = global ; Do not fall through to an `anonymous` endpoint for unmatched calls. ; This is the single most important line in the file. unidentified_request_count = 5 unidentified_request_period = 5 unidentified_request_prune_interval = 30 [transport-udp] type = transport protocol = udp bind = 0.0.0.0:{{ asterisk_sip_port }} ; The address Asterisk advertises in SDP. Without this, containers advertise ; their internal bridge IP and RTP arrives at an unroutable address — the ; classic "call connects but there is no audio" failure. external_media_address = {{ asterisk_external_ip }} external_signaling_address = {{ asterisk_external_ip }} local_net = {{ asterisk_local_net }} ; --------------------------------------------------------------------------- ; Hold Slayer endpoint ; --------------------------------------------------------------------------- ; Hold Slayer authenticates as this endpoint to place calls into the lab. ; Identify the endpoint by source address *and port*. Asterisk's default ; matching uses the From-header domain, which Hold Slayer populates from its ; SIP bind address (0.0.0.0 on a wildcard bind) — never a value Asterisk can ; match. Matching on where the packet came from sidesteps that. ; ; The port is essential when the softphone runs on the same host: a ; host-only match claims *every* packet from that address, so the ; softphone's REGISTER would be attributed to this endpoint and checked ; against the gateway's password ("Failed to authenticate", confusingly). ; Endpoints that authenticate by username (the softphone) must not be ; covered by an identify block. [hold-slayer] type = identify endpoint = hold-slayer match = {{ asterisk_match_host }}:{{ asterisk_gateway_port }} [hold-slayer] type = endpoint context = hold-slayer-lab disallow = all ; ulaw first: it is what the PSTN uses, so the lab exercises the same codec ; path a real trunk would. alaw as fallback. allow = ulaw allow = alaw auth = hold-slayer-auth aors = hold-slayer ; RFC 2833 out-of-band DTMF — what send_dtmf must produce. Setting this ; explicitly (rather than `auto`) means a DTMF failure is a real failure and ; not a negotiation fallback quietly rescuing it. dtmf_mode = rfc4733 direct_media = no force_rport = yes rewrite_contact = yes rtp_symmetric = yes [hold-slayer-auth] type = auth auth_type = userpass username = {{ asterisk_sip_username }} password = {{ asterisk_sip_password }} ; --------------------------------------------------------------------------- ; Softphone endpoint — the transfer target ; --------------------------------------------------------------------------- ; Asterisk is the registrar for devices, not Hold Slayer. A softphone REGISTERs ; here and the gateway transfers a live call to it by dialling extension 2001. ; ; Deliberate: Hold Slayer's own SIP listener answers 200 OK to any REGISTER ; with no digest challenge, so anything on the network could register as a ; device and receive transferred calls. Keeping registration in Asterisk means ; the lab does not depend on that path, and the softphone is authenticated. ; ; Test with the pjsua CLI built alongside the Python bindings: ; pjsua --null-audio --auto-answer=200 \ ; --id=sip:softphone@ \ ; --registrar=sip::21061 \ ; --realm='*' --username=softphone --password= \ ; --local-port= [softphone] type = endpoint context = hold-slayer-lab disallow = all allow = ulaw allow = alaw auth = softphone-auth aors = softphone dtmf_mode = rfc4733 direct_media = no force_rport = yes rewrite_contact = yes rtp_symmetric = yes [softphone-auth] type = auth auth_type = userpass username = {{ asterisk_softphone_username }} password = {{ asterisk_softphone_password }} [softphone] type = aor ; The device's contact is learned from its REGISTER rather than configured — ; a softphone's port is not known in advance. max_contacts = 1 remove_existing = yes ; No qualify: the pjsua CLI does not answer OPTIONS while sitting at its ; console prompt, so polling marks a perfectly working softphone Unavail and ; the dialplan refuses to ring it. Registration itself is the liveness signal ; here. A real hardphone answers OPTIONS and can have qualify re-enabled. qualify_frequency = 0 [hold-slayer] type = aor max_contacts = 2 remove_existing = yes qualify_frequency = 60