Skip to content

Trunks

A trunk is a SIP interconnect: a carrier, an upstream provider, a peer switch, or a customer’s PBX. The trunk entry itself carries the peer’s concrete identity — its source IPs, the URIs you dial to reach it, and its authorized caller IDs — while the shared behavior (translation contexts, caller-ID policy, codecs, timers) lives in its trunk profile.

trunks:
customer-pbx:
trunk-profile: customer-pbx-profile
ips:
- 198.51.100.10
uris:
- 198.51.100.10:5060
allowed-caller-ids:
- "_+1415555XXXX"
primary-caller-id: "+14155551000"
max-concurrent: 30
Field Required Meaning
trunk-profile yes The trunk profile governing this trunk’s behavior.
ips for inbound Source IPs authorized to send you calls as this trunk (below).
uris for outbound Destinations dialed, in order, when sending calls out this trunk (below).

Every trunk must have at least one of ips or uris — one-way trunks are fully supported. A trunk with only ips is inbound-only (origination); a trunk with only uris is outbound-only (termination). Using an inbound-only trunk as a dial target anywhere (a route destination, a translation target, an alias-trunk line, a ring-group fallback) is rejected at validation. | allowed-caller-ids | no | Caller IDs the peer may assert on inbound calls (below). Empty = no restriction. | | primary-caller-id | when profile mode is fixed | The trunk’s own number: the fixed-mode caller ID, and the identity asserted on 911 calls from this trunk. Must be a valid number when required. | | max-concurrent | no | Concurrent-call cap for this trunk, overriding the profile’s template. Zero/absent falls back to the profile; nothing anywhere = unlimited. |

Inbound trunk calls are authenticated by source IP: a call arriving at your anycast IP from an address in a trunk’s ips list is classified as that trunk, which selects the profile (and therefore the inbound translation context and caller-ID policy) for the call.

  • IP authentication requires your namespace’s edge-proxy to be set — the binding is to the pair (source IP, your anycast IP). Two tenants on different anycast IPs can legitimately share a source IP (two customers behind one carrier SBC); the same source IP on the same anycast IP can only belong to one namespace. A configuration claiming an IP already owned by another namespace on your edge IP is rejected at validation with the owning namespace identified.
  • Traffic from an authorized source IP aimed at a different tenant’s anycast IP is rejected at the edge — relevant when you move numbers or equipment between your own tenants; update the trunk entry in the namespace that should own the traffic.
  • A trunk with no ips can still be dialed outbound (delivery-only, e.g. a provider you only terminate to), but nothing can arrive as it.
  • Each ips entry must be a single IP address — CIDR ranges and hostnames are rejected at validation, because inbound classification is an exact source-IP match and a range would silently never match.

uris lists where the trunk is dialed, as host[:port] targets — your carrier’s SBCs, or the customer PBX’s address. Omit it entirely for an inbound-only trunk.

  • The profile’s uri-selection picks the order: sequential (listed order, primary/backup) or random (per-call shuffle, load spread).
  • Each URI rings for the profile’s ring-for (default 90 seconds).
  • Busy-level and transient failures retry the next URI of the same trunk; carrier-level failures escalate out of the trunk entirely (to the next destination when the dial came from a route).

Inbound caller-ID screening: allowed-caller-ids

Section titled “Inbound caller-ID screening: allowed-caller-ids”

allowed-caller-ids is the set of caller IDs the peer is authorized to assert on calls it sends you. Entries are exact numbers or Asterisk-style patterns (leading _), so a DID block is one entry:

allowed-caller-ids:
- "+14155551000" # main BTN
- "_+1415555XXXX" # their full DID range

Screening applies at ingress, against the caller ID after the profile’s caller-ID mode has run (a modify rewrite happens first, so the list validates the final value). A caller ID outside the list rejects the call with the invalid-caller-id treatment — the anti-spoofing backstop that keeps a compromised or misconfigured PBX from originating traffic as numbers it doesn’t own, and from having those numbers signed under your STIR/SHAKEN identity.

  • An empty list means no restriction — appropriate for carrier ingress trunks, where the whole PSTN’s numbers legitimately arrive.
  • With profile mode fixed, the list is not consulted: the asserted value is discarded and replaced with primary-caller-id, so there is nothing to screen.

max-concurrent caps simultaneous calls on this trunk (both directions count). It overrides the profile’s template value. Over-cap calls receive the all-circuits-busy treatment. Capacity is always tracked per individual trunk — profiles never pool capacity across trunks.

This is the knob that models purchased channel counts: sell a customer a 30-channel trunk group by setting max-concurrent: 30 on their trunk.

trunk-profiles:
customer-pbx-profile:
inbound-translation-context: from-customers
outbound-translation-context: to-customers
caller-id-mode: provided
attestation-mode: A
ring-for: 30
codecs: [ulaw, g722]
trunks:
acme-pbx:
trunk-profile: customer-pbx-profile
ips: [198.51.100.10]
uris: [198.51.100.10:5060]
allowed-caller-ids: ["_+1415555XXXX"]
primary-caller-id: "+14155551000"
max-concurrent: 30

Full attestation (A) is appropriate here because allowed-caller-ids pins the customer to numbers you assigned them.

Carrier termination with redundant gateways

Section titled “Carrier termination with redundant gateways”
trunks:
carrier-a:
trunk-profile: carrier-egress
uris:
- sbc1.carrier-a.example:5060
- sbc2.carrier-a.example:5060
max-concurrent: 500

No ips (this direction is outbound-only; the carrier’s inbound side is a separate trunk), two SBCs tried per the profile’s uri-selection.

trunks:
carrier-a-origination:
trunk-profile: carrier-ingress
ips:
- 203.0.113.20
- 203.0.113.21

Any caller ID is accepted (allowed-caller-ids omitted — this is the PSTN), and the profile’s inbound context delivers DIDs. No uris — this is a one-way, inbound-only trunk; the carrier’s termination side is the separate carrier-a trunk above.