Extensions 7101 and 7102 can already call each other, and the previous episode added an IVR. This exercise adds one SIP trunk and lets these authenticated users dial a single authorized test destination with a local prefix of 9. Configuration loading, registration and a completed call are separate checks.
The examples were checked against FreeSWITCH v1.10.12 vanilla templates and source. They have not been tested against a live carrier. Replace the example credentials, domain and destination locally before deployment. Without provisioned trunk details, only the file structure can be checked. Number format, caller identity, concurrency and charges depend on the service contract.
Establish the trunk's authentication model
A registering trunk sends REGISTER with carrier credentials and maintains a contact binding. An IP-authenticated trunk normally needs no registration. register="false" disables REGISTER; it does not configure carrier allowlists, firewall rules or inbound ACLs.
Collect the SIP host and port, required transport, account and authentication realm, permitted caller identity, destination format, actual public egress address and an authorized test destination. Confirm whether registration and calls use different servers. This example assumes a trunk that supports UDP. TLS certificates and public NAT are covered in later episodes.
Inspect the instance in fs_cli:
eval $${conf_dir}
sofia status profile external
sofia status profile internal reg
CONF below is the returned configuration directory. The external profile must already be running. The internal path for 7101 and 7102 must authenticate this INVITE; a registration record alone does not authenticate every subsequent request. Preserve existing authentication and source restrictions.
Find the gateway configuration directory
A gateway defines a trunk, not a SIP extension or a queue agent. In vanilla, CONF/sip_profiles/external.xml includes external/*.xml inside gateways, so the new files belong in CONF/sip_profiles/external/. Keep the existing include:
<gateways>
<!-- 位于external这个Profile内部,读取它所属的线路文件 -->
<X-PRE-PROCESS cmd="include" data="external/*.xml"/>
</gateways>
Back up the parent configuration and check that training_carrier_reg and training_carrier_ip are unused. The filename organizes configuration; bridge references the gateway's name. A fragment uses an include wrapper around gateway rather than defining another profile.
Define a registering trunk
Create CONF/sip_profiles/external/06_carrier_reg.xml:
<include>
<!-- 本地线路名,与后面bridge里的名称一致 -->
<gateway name="training_carrier_reg">
<!-- 运营商分配的SIP账号和口令,必须在本机替换 -->
<param name="username" value="YOUR_TRUNK_USER"/>
<param name="password" value="LOCAL_TRUNK_PASSWORD"/>
<!-- 呼叫目的服务器;此处为保留示例域名 -->
<param name="proxy" value="sip.carrier.example"/>
<!-- 鉴权域,按运营商给出的值填写 -->
<param name="realm" value="YOUR_AUTH_REALM"/>
<!-- From身份与鉴权账号可能不同,由线路要求决定 -->
<param name="from-user" value="YOUR_FROM_USER"/>
<param name="from-domain" value="sip.carrier.example"/>
<!-- 注册型线路发送REGISTER,示例按支持UDP的线路编写 -->
<param name="register" value="true"/>
<param name="register-transport" value="udp"/>
<!-- 请求注册有效期与失败重试间隔,单位均为秒 -->
<param name="expire-seconds" value="3600"/>
<param name="retry-seconds" value="30"/>
<!-- 来电继续进入public,不开放整个default -->
<param name="context" value="public"/>
</gateway>
</include>
username and password are carrier credentials, unrelated to the 7101 extension password. XML attribute values need escaping: encode ampersand, less-than and double quote as &, < and ". Parsing must still recover the original password. Limit file-read access to the service and necessary administrators.
proxy identifies the SIP request target. realm identifies the Digest authentication realm and may differ. from-user and from-domain set the From identity; the provider may require a fixed account or allocated number. Using 7101 does not grant permission to present it on the public network. Episode 08 expands on caller identity headers.
register=true enables registration. register-transport=udp chooses REGISTER transport, not the profile's listeners, and does not by itself establish how every outbound call is transported. expire-seconds=3600 requests a one-hour binding; the provider may negotiate a different lifetime. retry-seconds=30 is the retry interval after registration failure. Both values are seconds.
context=public keeps inbound routing separate. Registration does not generate the DID mappings from episode 04. Inbound calls still require inspection of the actual received destination and its route. Outbound calling is the primary acceptance test here.
Define an IP-authenticated alternative
Use CONF/sip_profiles/external/06_carrier_ip.xml for this model. Select the alternative that matches the provisioned service. 203.0.113.10 is a documentation address, not a working carrier endpoint:
<include>
<!-- 与注册型二选一测试;203.0.113.10是文档地址,须替换 -->
<gateway name="training_carrier_ip">
<!-- 对端SIP地址及端口按线路资料填写 -->
<param name="proxy" value="203.0.113.10:5060"/>
<!-- 不发送REGISTER,运营商需另行放行本机实际出口IP -->
<param name="register" value="false"/>
<!-- 保留public入站路由;这个参数不自动生成ACL -->
<param name="context" value="public"/>
</gateway>
</include>
This version permits omission of username/password when register=false. A provider that does not require registration but challenges INVITE with credentials still needs the appropriate credentials; that is not an IP-only service. The provider must allow the source address it actually observes, which may differ from the server's interface address.
A non-registering gateway normally shows NOREG and can be locally marked UP as soon as it loads. That is not proof of carrier authorization or a successful test call.
Add a narrowly scoped outbound rule
Create CONF/dialplan/default/06_training_outbound.xml. Replace YOUR_TEST_NUMBER with the single authorized destination in the carrier's accepted digits-only format, excluding the local 9 prefix. Keep the surrounding parentheses and anchors. Until replaced, this example does not match ordinary telephone dialing.
<include>
<!-- 仅用于已鉴权内部分机的受控外呼测试 -->
<extension name="training-outbound-06">
<!-- 依据本次INVITE鉴权账号,不能用可改写的显示号码代替 -->
<condition field="${sip_auth_username}" expression="^(7101|7102)$"/>
<!-- YOUR_TEST_NUMBER替换为唯一授权测试被叫的纯数字号码 -->
<condition field="destination_number" expression="^9(YOUR_TEST_NUMBER)$">
<!-- 记录命中标记,便于关联新产生的外呼腿 -->
<action application="log" data="NOTICE training-outbound-06"/>
<!-- 限制本次bridge的等待,单位秒,不限制已接通通话时长 -->
<action application="set" data="call_timeout=30"/>
<!-- 9是本地接入前缀,捕获组$1才是发送给线路的被叫 -->
<action application="bridge" data="sofia/gateway/training_carrier_reg/$1"/>
<!-- 桥接返回后的测试流程到此结束 -->
<action application="hangup"/>
</condition>
</extension>
</include>
sip_auth_username identifies the account authenticated for this request. A displayed caller_id_number is not an authentication credential. If the authentication variable is empty, inspect the internal authentication path and variable source rather than removing the condition. This lab rule depends on correct existing authentication and routing; it is not a complete outbound authorization system.
The second condition matches only 9 followed by the designated destination. Capture group $1 removes the local prefix before sending the called number to the carrier. For the IP alternative, change only the gateway name in bridge to training_carrier_ip. call_timeout=30 bounds bridge waiting in seconds; it does not impose a 30-second duration on an answered call. There is no early answer action.
Confirm that default.xml still includes the directory and that an earlier broad rule does not consume the prefixed destination. General normalization and prefix manipulation are covered next. Real carrier tests may incur charges; use a destination you are authorized to call and can answer.
Load configuration, then test the call
For a newly added gateway, run:
reloadxml
sofia profile external rescan
sofia status gateway training_carrier_reg
Use training_carrier_ip in the status query for the alternative. reloadxml updates XML; rescan lets the running profile discover new gateways. An existing in-memory gateway is not necessarily replaced by editing its file and reloading XML. A successful registering trunk commonly reaches REGED; NOREG is expected for a trunk configured not to register.
From 7101, dial 9 followed by the substituted destination. Check the local route marker, remote ringing, answer, two-way speech and hangup from each end. Repeat from 7102. Verify that exactly the local prefix was removed and that the presented caller identity is permitted. A successful registration does not validate SDP, RTP addressing or codec negotiation for a call.
To change an existing gateway, choose a maintenance window that permits interruption to this trunk. Disable its test route, finish associated calls and remove the old in-memory object before scanning the updated definition. killgw affects registration and new calls on the trunk; it is not an interruption-free update:
sofia profile external killgw training_carrier_reg
Wait until status confirms the old object has been removed, then rescan external and inspect it again. The command marks an object for deletion, so +OK is not confirmation that removal has fully completed. Do not use all for this single-trunk operation. No profile restart is needed for this exercise.
Useful options beyond the minimal examples
Use auth-username when the authentication name differs from the account. register-proxy selects a separate registration target; outbound-proxy addresses a separate outbound routing proxy. These fields solve different routing problems.
ping sends OPTIONS at a seconds-based interval. A provider that ignores or rejects such probes can cause an otherwise callable trunk to be marked DOWN. The example leaves probing disabled until the provider's policy is understood. OPTIONS also does not validate call media.
extension and extension-in-contact affect the Contact user and associated inbound addressing; they do not create an internal SIP user. Recheck episode 04's inbound routes after changing them. Even commented template parameters require version verification: this version's gateway parameter parser does not accept cid-type, so it is omitted rather than copied.
Diagnose failures and roll back
If the gateway cannot be found, inspect the parent include, profile name, XML errors, duplicate names and whether rescan ran. If edits still appear stale, check for the existing in-memory object and follow the maintenance procedure for that trunk.
A single 401 or 407 can be an ordinary authentication challenge. Inspect the result of the authenticated retry before treating it as failure. Continued failures call for checking account, password, realm and provider restrictions. RFC 3261 distinguishes registrar/UAS and proxy challenges. A timeout without a response instead directs attention to name resolution, target, transport and network access.
If REGED is followed by rejected calls, compare destination format, permitted caller identity, balance and account permissions with the actual response. If an IP trunk is UP but cannot call, verify the egress address observed by the carrier. For one-way audio, inspect RTP addresses, ports and codecs rather than repeatedly changing registration credentials.
Remove the new outbound rule and run reloadxml to stop new tests. After associated calls finish, move the new gateway file out of the included directory, kill only that gateway and wait for removal. For a modified existing trunk, restore its backup, rescan and verify it. Recheck extension calling, queue 7190 and IVR 7180; none needs rebuilding.
Sources and applicability
Checked on 2026-11-03 against the v1.10.12 gateway template, external profile, gateway parser, loading commands and the current gateway manual. Live acceptance testing requires provisioned service details and a controlled environment.