First steps for SIP Bridge
This commit is contained in:
parent
409a12ea89
commit
824e235191
52
acSipBridge/astrocom.md
Normal file
52
acSipBridge/astrocom.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
AstroCom integration for freePBX (Originally made for TandmX by @lachesis_._ @lachesis_._)
|
||||||
|
1. (caveats: assumes full exchange, assumes 4 digit extensions, assumes you're okay with AstroCom users dialing anything 4-digit on your switch)
|
||||||
|
2. Put the following in your `globals_custom.conf`:
|
||||||
|
```
|
||||||
|
astrocomkey=(long-key-you-got-from-admins)
|
||||||
|
```
|
||||||
|
3. Put the following in your `iax_custom.conf`:
|
||||||
|
```
|
||||||
|
[from-astrocom]
|
||||||
|
type=user
|
||||||
|
username=from-astrocom
|
||||||
|
secret=(short-secret-you-sent-to-astrocom)
|
||||||
|
auth=md5
|
||||||
|
encryption=yes
|
||||||
|
context=from-astrocom
|
||||||
|
```
|
||||||
|
4. Put the following in `extensions_custom.conf`, *change 777 to your AstroCom exchange prefix*, and uncomment one or both blocks directly below
|
||||||
|
```
|
||||||
|
[from-internal-additional-custom]
|
||||||
|
; Change 777 to your exchange prefix
|
||||||
|
; Uncomment for 7 digit dialing to AstroCom
|
||||||
|
;exten => _XXXXXXX,1,NoOp
|
||||||
|
; same => n,Set(CALLERID(num)=777${CALLERID(num)})
|
||||||
|
; same => n,Goto(astrocom-dial,${EXTEN},1)
|
||||||
|
; same => n,Hangup
|
||||||
|
|
||||||
|
; Uncomment for 1-300-XXX-XXXX to AstroCom
|
||||||
|
;exten => _1300XXXXXXX,1,NoOp
|
||||||
|
; same => n,Set(CALLERID(num)=777${CALLERID(num)})
|
||||||
|
; same => n,Goto(astrocom-dial,${EXTEN:4},1)
|
||||||
|
; same => n,Hangup
|
||||||
|
|
||||||
|
[astrocom-dial]
|
||||||
|
exten => _X!,1,Set(number=${EXTEN})
|
||||||
|
same => n,Set(lookup=${CURL(https://api.astrocom.tel/api/v1/route/${astrocomkey}/${FILTER(0-9,${CALLERID(num)})}/${FILTER(0-9,${number})})})
|
||||||
|
same => n,GotoIf($["${lookup}"=="local"]?local:long)
|
||||||
|
same => n(local),Goto(astrocom-exchange,${number},1)
|
||||||
|
same => n(long),Dial(${lookup})
|
||||||
|
same => n,Hangup
|
||||||
|
|
||||||
|
[from-astrocom]
|
||||||
|
exten => _X!,1,NoOp()
|
||||||
|
same => n,Goto(astrocom-exchange,${EXTEN},1)
|
||||||
|
same => n,Hangup
|
||||||
|
|
||||||
|
; Change 777 to your exchange prefix
|
||||||
|
[astrocom-exchange]
|
||||||
|
exten => _777XXXX,1,Goto(from-internal,${EXTEN:3},1)
|
||||||
|
same => n,Hangup
|
||||||
|
```
|
||||||
|
|
||||||
|
Literally picked straight from tandmx (will make our own docs eventually, but this'll get us going)
|
||||||
161
acSipBridge/extensions.conf
Normal file
161
acSipBridge/extensions.conf
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
; =====================================================; GLOBALS REQUIRED (globals.conf or globals_custom.conf)
|
||||||
|
; -------------------------------------------------------------
|
||||||
|
; [globals]
|
||||||
|
; BRIDGE1_APIKEY=<routes.apiKey for bridge 1>
|
||||||
|
; BRIDGE1_EXCHANGE=777 ; NXX prefix — used to build the outbound ANI only,
|
||||||
|
; ; NOT applied to inbound DIDs (full number passes through)
|
||||||
|
; BRIDGE2_APIKEY=<routes.apiKey for bridge 2>
|
||||||
|
; BRIDGE2_EXCHANGE=888
|
||||||
|
; ; ...add one pair per bridge; AstroCom SIP Bridge -- Dialplan (extensions.conf)
|
||||||
|
; /etc/asterisk/extensions.conf
|
||||||
|
;
|
||||||
|
; CALL FLOWS
|
||||||
|
; -------------------------------------------------------------
|
||||||
|
;
|
||||||
|
; INBOUND (AstroCom -> downstream PBX via PJSIP)
|
||||||
|
; -----------------------------------------------
|
||||||
|
; AstroCom delivers the full 7-digit number, e.g. 7771234.
|
||||||
|
; The full number is forwarded as-is to the downstream PBX as
|
||||||
|
; the SIP Request-URI / To: user (DID). The PBX is responsible
|
||||||
|
; for routing it internally however it sees fit.
|
||||||
|
;
|
||||||
|
; AstroCom --IAX2--> [bridgeN-from-astrocom]
|
||||||
|
; |
|
||||||
|
; Pass full DID (e.g. 7771234) to PBX
|
||||||
|
; |
|
||||||
|
; Dial PJSIP/7771234@bridgeN-pbx
|
||||||
|
; |
|
||||||
|
; v
|
||||||
|
; Downstream PBX
|
||||||
|
;
|
||||||
|
; OUTBOUND (downstream PBX -> AstroCom via IAX2)
|
||||||
|
; ------------------------------------------------
|
||||||
|
; The PBX dials the full 7-digit AstroCom number.
|
||||||
|
; The bridge prepends the local exchange so the ANI is also
|
||||||
|
; 7 digits, then hits the AstroCom routing API:
|
||||||
|
;
|
||||||
|
; GET https://api.astrocom.tel/api/v1/route/<apiKey>/<ANI>/<number>
|
||||||
|
;
|
||||||
|
; The API returns one of:
|
||||||
|
; "local"
|
||||||
|
; --> same block; route to this bridge's own SIP PBX
|
||||||
|
; "IAX2/<auth>:<secret>@<host>:<port>/<number>"
|
||||||
|
; --> dial that URI verbatim
|
||||||
|
; "<MSG_ROUTE_ADDRESS>/4xx"
|
||||||
|
; --> rejected; play busy/congestion toward PBX
|
||||||
|
;
|
||||||
|
; Downstream PBX --SIP--> [bridgeN-from-pbx]
|
||||||
|
; |
|
||||||
|
; CURL api.astrocom.tel/api/v1/route/...
|
||||||
|
; |
|
||||||
|
; +----------+----------+
|
||||||
|
; local IAX2 URI
|
||||||
|
; | |
|
||||||
|
; Dial PJSIP/XXXX@bridgeN-pbx Dial ${lookup}
|
||||||
|
;
|
||||||
|
; ISOLATION
|
||||||
|
; -------------------------------------------------------------
|
||||||
|
; * Every bridge has exactly two contexts; they share nothing.
|
||||||
|
; * [default] silently drops anything with no context match.
|
||||||
|
; * Inter-bridge calls route through AstroCom automatically --
|
||||||
|
; no extra config needed here.
|
||||||
|
;
|
||||||
|
; GLOBALS REQUIRED (globals.conf or globals_custom.conf)
|
||||||
|
; -------------------------------------------------------------
|
||||||
|
; [globals]
|
||||||
|
; BRIDGE1_APIKEY=<routes.apiKey for bridge 1>
|
||||||
|
; BRIDGE1_EXCHANGE=777 ; NXX prefix (3 digits) for bridge 1
|
||||||
|
; BRIDGE2_APIKEY=<routes.apiKey for bridge 2>
|
||||||
|
; BRIDGE2_EXCHANGE=888
|
||||||
|
; ; ...add one pair per bridge
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
[default]
|
||||||
|
exten => _X!,1,Verbose(2,DROP: ${EXTEN} landed in [default] -- no matching context)
|
||||||
|
same => n,Hangup(21)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; --- BRIDGE 1 -----------------------------------------------
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
; Inbound from AstroCom -> forward full DID to PBX
|
||||||
|
; Context name == routes.auth == IAX2 section name in iax.conf
|
||||||
|
[bridge1-from-astrocom]
|
||||||
|
exten => _XXXXXXX,1,Verbose(2,BRIDGE1 inbound from AstroCom: ${CALLERID(all)} -> ${EXTEN})
|
||||||
|
same => n,Dial(PJSIP/${EXTEN}@bridge1-pbx,30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
; Outbound from Bridge-1 PBX -> CURL AstroCom API -> IAX2
|
||||||
|
[bridge1-from-pbx]
|
||||||
|
exten => _XXXXXXX,1,Verbose(2,BRIDGE1 outbound from PBX: ${CALLERID(all)} -> ${EXTEN})
|
||||||
|
; Build the 7-digit ANI: exchange prefix + bare extension from CallerID
|
||||||
|
same => n,Set(ANI=${BRIDGE1_EXCHANGE}${FILTER(0-9,${CALLERID(num)})})
|
||||||
|
; Ask AstroCom where to send this call
|
||||||
|
same => n,Set(lookup=${CURL(https://api.astrocom.tel/api/v1/route/${BRIDGE1_APIKEY}/${ANI}/${EXTEN})})
|
||||||
|
same => n,Verbose(2,BRIDGE1 AstroCom lookup: ${lookup})
|
||||||
|
; "local" -- callee shares our block, route to our own SIP PBX
|
||||||
|
same => n,GotoIf($["${lookup}" = "local"]?local)
|
||||||
|
; Empty or error URL -- reject
|
||||||
|
same => n,GotoIf($["${lookup}" = ""]?reject)
|
||||||
|
; Valid IAX2 URI -- dial it verbatim
|
||||||
|
same => n,Dial(${lookup},30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
; Local path -- strip exchange prefix, dial extension on own PBX
|
||||||
|
same => n(local),Verbose(2,BRIDGE1 local call: routing ${EXTEN} to own PBX)
|
||||||
|
same => n,Dial(PJSIP/${EXTEN}@bridge1-pbx,30,t)
|
||||||
|
same => n,Hangup()
|
||||||
|
; Error paths
|
||||||
|
same => n(reject),Verbose(2,BRIDGE1 AstroCom rejected call: ${lookup})
|
||||||
|
same => n,Congestion(5)
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; --- BRIDGE 3 (copy & uncomment for each additional bridge) -
|
||||||
|
; ============================================================
|
||||||
|
; Also add BRIDGE3_APIKEY and BRIDGE3_EXCHANGE to globals.conf.
|
||||||
|
;
|
||||||
|
;[bridge3-from-astrocom]
|
||||||
|
;exten => _X!,1,Verbose(2,BRIDGE3 inbound: ${CALLERID(all)} -> ${EXTEN})
|
||||||
|
; same => n,Dial(PJSIP/${EXTEN}@bridge3-pbx,30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
;
|
||||||
|
;[bridge3-from-pbx]
|
||||||
|
;exten => _X!,1,Verbose(2,BRIDGE3 outbound: ${CALLERID(all)} -> ${EXTEN})
|
||||||
|
; same => n,Set(ANI=${BRIDGE3_EXCHANGE}${FILTER(0-9,${CALLERID(num)})})
|
||||||
|
; same => n,Set(lookup=${CURL(https://api.astrocom.tel/api/v1/route/${BRIDGE3_APIKEY}/${ANI}/${EXTEN})})
|
||||||
|
; same => n,GotoIf($["${lookup}" = "local"]?local)
|
||||||
|
; same => n,GotoIf($["${lookup}" = ""]?reject)
|
||||||
|
; same => n,Dial(${lookup},30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
; same => n(local),Dial(PJSIP/${EXTEN}@bridge3-pbx,30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
; same => n(reject),Congestion(5)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; --- OPTIONAL: Direct SIP inter-bridge shortcut -------------
|
||||||
|
;
|
||||||
|
; Bridges can already call each other through AstroCom with
|
||||||
|
; zero extra config. If you want direct SIP routing between
|
||||||
|
; bridges (no AstroCom hop), add a higher-priority pattern for
|
||||||
|
; the other bridge's block BEFORE the _X! catch-all.
|
||||||
|
;
|
||||||
|
; Example -- Bridge-1 calling Bridge-2's 888XXXX block directly:
|
||||||
|
;
|
||||||
|
;[bridge1-from-pbx]
|
||||||
|
;exten => _888XXXX,1,Verbose(2,BRIDGE1->BRIDGE2 direct: ${EXTEN})
|
||||||
|
; same => n,Dial(PJSIP/${EXTEN}@bridge2-pbx,30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
;
|
||||||
|
; (The _X! rule below then handles all other numbers normally.)
|
||||||
|
; ============================================================
|
||||||
148
acSipBridge/extensions.conf.bak
Normal file
148
acSipBridge/extensions.conf.bak
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
; ============================================================
|
||||||
|
; AstroCom SIP Bridge — Dialplan (extensions.conf)
|
||||||
|
; /etc/asterisk/extensions.conf
|
||||||
|
;
|
||||||
|
; CALL FLOW
|
||||||
|
; ─────────────────────────────────────────────────────────────
|
||||||
|
;
|
||||||
|
; INBOUND from AstroCom (IAX2 → SIP toward downstream PBX):
|
||||||
|
;
|
||||||
|
; AstroCom ──IAX2──▶ [bridgeN-from-astrocom]
|
||||||
|
; │
|
||||||
|
; Bridge to SIP peer
|
||||||
|
; │
|
||||||
|
; SIP/bridgeN-pbx/<EXTEN>
|
||||||
|
; │
|
||||||
|
; ▼
|
||||||
|
; Downstream PBX / phone
|
||||||
|
;
|
||||||
|
; OUTBOUND from downstream PBX (SIP → IAX2 toward AstroCom):
|
||||||
|
;
|
||||||
|
; Downstream PBX ──SIP──▶ [bridgeN-from-pbx]
|
||||||
|
; │
|
||||||
|
; Bridge to IAX2 peer
|
||||||
|
; │
|
||||||
|
; IAX2/bridge1-astrocom/<EXTEN>
|
||||||
|
; │
|
||||||
|
; ▼
|
||||||
|
; AstroCom
|
||||||
|
;
|
||||||
|
; ISOLATION
|
||||||
|
; ─────────────────────────────────────────────────────────────
|
||||||
|
; • Each bridge uses its own pair of contexts
|
||||||
|
; (bridgeN-from-astrocom / bridgeN-from-pbx).
|
||||||
|
; • No cross-bridge dialplan references exist UNLESS you
|
||||||
|
; explicitly uncomment the inter-bridge section at the
|
||||||
|
; bottom. Until then each bridge is a closed island.
|
||||||
|
; • The [default] context is intentionally empty / drops
|
||||||
|
; calls to prevent anything landing there from escaping.
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Safety net — calls that arrive in no recognised context are
|
||||||
|
; silently dropped.
|
||||||
|
; ============================================================
|
||||||
|
[default]
|
||||||
|
exten => _X.,1,Verbose(2,DROP: call to ${EXTEN} landed in [default] — no context matched)
|
||||||
|
same => n,Hangup(21)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; ─── BRIDGE 1 ───────────────────────────────────────────────
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
; ------ Inbound from AstroCom → forward to Bridge-1 PBX ----
|
||||||
|
; This context name MUST equal routes.auth for this bridge.
|
||||||
|
[bridge1-from-astrocom]
|
||||||
|
; Accept any extension that AstroCom sends for this block.
|
||||||
|
exten => _X.,1,Verbose(2,BRIDGE1 inbound from AstroCom: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
same => n,Set(CALLERID(name)=${CALLERID(name)})
|
||||||
|
same => n,Dial(SIP/bridge1-pbx/${EXTEN},30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
; ------ Inbound from Bridge-1 PBX → forward to AstroCom ----
|
||||||
|
[bridge1-from-pbx]
|
||||||
|
exten => _X.,1,Verbose(2,BRIDGE1 outbound from PBX: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
; Strip any leading '9' access code the PBX may prepend, e.g. "9XXXXXXX"
|
||||||
|
; Uncomment/adapt if needed:
|
||||||
|
;same => n,Set(EXTEN=${EXTEN:1})
|
||||||
|
same => n,Set(CALLERID(name)=${CALLERID(name)})
|
||||||
|
same => n,Dial(IAX2/bridge1-astrocom/${EXTEN},30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; ─── BRIDGE 2 ───────────────────────────────────────────────
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
[bridge2-from-astrocom]
|
||||||
|
exten => _X.,1,Verbose(2,BRIDGE2 inbound from AstroCom: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
same => n,Set(CALLERID(name)=${CALLERID(name)})
|
||||||
|
same => n,Dial(SIP/bridge2-pbx/${EXTEN},30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
[bridge2-from-pbx]
|
||||||
|
exten => _X.,1,Verbose(2,BRIDGE2 outbound from PBX: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
same => n,Set(CALLERID(name)=${CALLERID(name)})
|
||||||
|
same => n,Dial(IAX2/bridge2-astrocom/${EXTEN},30,t)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?congestion)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
|
||||||
|
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
|
||||||
|
same => n,Hangup()
|
||||||
|
|
||||||
|
same => n(congestion),Congestion(5)
|
||||||
|
same => n(busy),Busy(5)
|
||||||
|
same => n(noanswer),Hangup(19)
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; ─── BRIDGE 3 (template — duplicate & uncomment) ────────────
|
||||||
|
; ============================================================
|
||||||
|
;[bridge3-from-astrocom]
|
||||||
|
;exten => _X.,1,Verbose(2,BRIDGE3 inbound from AstroCom: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
; same => n,Dial(SIP/bridge3-pbx/${EXTEN},30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
;
|
||||||
|
;[bridge3-from-pbx]
|
||||||
|
;exten => _X.,1,Verbose(2,BRIDGE3 outbound from PBX: ${CALLERID(all)} → ${EXTEN})
|
||||||
|
; same => n,Dial(IAX2/bridge3-astrocom/${EXTEN},30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; ─── OPTIONAL: Inter-bridge dialling ────────────────────────
|
||||||
|
;
|
||||||
|
; If you want Bridge-1's PBX to be able to call Bridge-2's
|
||||||
|
; numbers *directly* (without round-tripping through AstroCom)
|
||||||
|
; you can include the other bridge's inbound SIP context here.
|
||||||
|
;
|
||||||
|
; Example: in [bridge1-from-pbx], add a pattern for Bridge-2's
|
||||||
|
; number block *before* the catch-all _X. rule so it is
|
||||||
|
; preferred. Bridge-2's block in AstroCom is consulted to
|
||||||
|
; determine the number range.
|
||||||
|
;
|
||||||
|
;[bridge1-from-pbx]
|
||||||
|
;exten => _7XXXX,1,Verbose(2,BRIDGE1→BRIDGE2 direct: ${EXTEN})
|
||||||
|
; same => n,Dial(SIP/bridge2-pbx/${EXTEN},30,t)
|
||||||
|
; same => n,Hangup()
|
||||||
|
;
|
||||||
|
; Without uncommenting the above, bridge1 and bridge2 can still
|
||||||
|
; reach each other — calls just travel via AstroCom as normal.
|
||||||
|
; ============================================================
|
||||||
0
acSipBridge/globals.conf
Normal file
0
acSipBridge/globals.conf
Normal file
71
acSipBridge/iax.conf
Normal file
71
acSipBridge/iax.conf
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
; ============================================================
|
||||||
|
; AstroCom SIP Bridge — IAX2 Configuration (chan_iax2)
|
||||||
|
; /etc/asterisk/iax.conf
|
||||||
|
;
|
||||||
|
; HOW ASTROCOM CALLS THIS BRIDGE
|
||||||
|
; ──────────────────────────────
|
||||||
|
; When AstroCom routes a call here it dials:
|
||||||
|
; IAX2/<routes.auth>:<routes.secret>@<routes.server>:<routes.port>/<number>
|
||||||
|
;
|
||||||
|
; That means:
|
||||||
|
; • The SECTION NAME (in brackets) IS the IAX2 username AstroCom
|
||||||
|
; authenticates with. It must equal routes.auth exactly.
|
||||||
|
; • 'secret' must equal routes.secret exactly.
|
||||||
|
; • 'context' is where the call lands in extensions.conf.
|
||||||
|
; It must also equal routes.auth (the dialplan context is
|
||||||
|
; named identically for clarity).
|
||||||
|
; • type=user — AstroCom calls us; we never initiate an IAX2
|
||||||
|
; connection back to AstroCom. Outbound calls use a
|
||||||
|
; dynamically-generated IAX2 URI from the routing API
|
||||||
|
; (handled in extensions.conf) and need no peer config here.
|
||||||
|
;
|
||||||
|
; NAT NOTE
|
||||||
|
; ────────
|
||||||
|
; Do NOT use 'register =>'. If this server has a dynamic IP,
|
||||||
|
; use tools/astrocom_dynamic_ip.sh (or the /api/v1/user/update
|
||||||
|
; endpoint) to keep routes.server current in AstroCom.
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
[general]
|
||||||
|
bindport=4569
|
||||||
|
bindaddr=0.0.0.0
|
||||||
|
iaxcompat=yes
|
||||||
|
authdebug=no
|
||||||
|
bandwidth=high
|
||||||
|
jitterbuffer=yes
|
||||||
|
forcejitterbuffer=yes
|
||||||
|
dropcount=2
|
||||||
|
maxjitterbuffer=1000
|
||||||
|
jittertargetextra=40
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Shared user template
|
||||||
|
; ============================================================
|
||||||
|
[bridge-iax-tmpl](!)
|
||||||
|
type=user
|
||||||
|
auth=md5
|
||||||
|
encryption=yes
|
||||||
|
disallow=all
|
||||||
|
allow=ulaw
|
||||||
|
allow=alaw
|
||||||
|
allow=g729
|
||||||
|
qualify=yes
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 1
|
||||||
|
; routes.auth = bridge1-from-astrocom ← section name
|
||||||
|
; routes.secret = BRIDGE1_IAX_SECRET
|
||||||
|
; routes.server = <this server's public IP>
|
||||||
|
; routes.port = 4569
|
||||||
|
; ============================================================
|
||||||
|
[bridge1-from-astrocom](bridge-iax-tmpl)
|
||||||
|
secret=20fbb81ba96091af1fe45858a070c7 ; Must equal routes.secret in AstroCom
|
||||||
|
context=bridge1-from-astrocom ; Must equal routes.auth in AstroCom
|
||||||
|
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 3 (copy this block for every additional bridge)
|
||||||
|
; ============================================================
|
||||||
|
;[bridge3-from-astrocom](bridge-iax-tmpl)
|
||||||
|
;secret=BRIDGE3_IAX_SECRET
|
||||||
|
;context=bridge3-from-astrocom
|
||||||
112
acSipBridge/pjsip.conf
Normal file
112
acSipBridge/pjsip.conf
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
; ============================================================
|
||||||
|
; AstroCom SIP Bridge — PJSIP Configuration (chan_pjsip)
|
||||||
|
; /etc/asterisk/pjsip.conf
|
||||||
|
;
|
||||||
|
; Downstream PBXes REGISTER to this server.
|
||||||
|
; Each bridge requires three stanzas sharing the same base name:
|
||||||
|
;
|
||||||
|
; [bridgeN-pbx] type=endpoint — codecs, context, links to auth/aor
|
||||||
|
; [bridgeN-pbx] type=aor — stores the registered contact URI
|
||||||
|
; [bridgeN-pbx-auth] type=auth — username / password the PBX uses
|
||||||
|
;
|
||||||
|
; The PBX must be configured to register with:
|
||||||
|
; Registrar : sip:<this server's IP>:5060
|
||||||
|
; Username : bridgeN-pbx (must match auth.username below)
|
||||||
|
; Password : the 'password' value in [bridgeN-pbx-auth]
|
||||||
|
;
|
||||||
|
; Outbound calls to this PBX from the dialplan:
|
||||||
|
; Dial(PJSIP/${EXTEN}@bridgeN-pbx)
|
||||||
|
; Asterisk substitutes the registered contact URI automatically.
|
||||||
|
;
|
||||||
|
; Disable/remove sip.conf (or set chan_sip bindport=0) so both
|
||||||
|
; modules do not compete for port 5060.
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Transport — one UDP listener for all bridges
|
||||||
|
; ============================================================
|
||||||
|
[bridge-transport]
|
||||||
|
type=transport
|
||||||
|
protocol=udp
|
||||||
|
bind=0.0.0.0:5060
|
||||||
|
; For NAT — uncomment and fill in:
|
||||||
|
;local_net=192.168.0.0/16
|
||||||
|
;external_signaling_address=PUBLIC_IP
|
||||||
|
;external_media_address=PUBLIC_IP
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Shared endpoint template
|
||||||
|
; ============================================================
|
||||||
|
[bridge-endpoint-tmpl](!)
|
||||||
|
type=endpoint
|
||||||
|
transport=bridge-transport
|
||||||
|
disallow=all
|
||||||
|
allow=ulaw
|
||||||
|
allow=alaw
|
||||||
|
allow=g729
|
||||||
|
dtmf_mode=rfc4733
|
||||||
|
; Force media through this server — required if either side is behind NAT
|
||||||
|
direct_media=no
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 1
|
||||||
|
; Auth username : bridge1-pbx
|
||||||
|
; Auth password : (set below — must match PBX registration password)
|
||||||
|
; Inbound calls from this PBX land in [bridge1-from-pbx] (extensions.conf)
|
||||||
|
; ============================================================
|
||||||
|
[bridge1-pbx](bridge-endpoint-tmpl)
|
||||||
|
type=endpoint
|
||||||
|
auth=bridge1-pbx-auth
|
||||||
|
aors=bridge1-pbx
|
||||||
|
context=bridge1-from-pbx
|
||||||
|
|
||||||
|
[bridge1-pbx-auth]
|
||||||
|
type=auth
|
||||||
|
auth_type=userpass
|
||||||
|
username=bridge1-pbx
|
||||||
|
password=1242ebce8b420ee4723887ffe0a01211330851776862e6021f680f1406c94eff
|
||||||
|
|
||||||
|
[bridge1-pbx]
|
||||||
|
type=aor
|
||||||
|
max_contacts=1
|
||||||
|
remove_existing=yes
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 2
|
||||||
|
; ============================================================
|
||||||
|
[bridge2-pbx](bridge-endpoint-tmpl)
|
||||||
|
type=endpoint
|
||||||
|
auth=bridge2-pbx-auth
|
||||||
|
aors=bridge2-pbx
|
||||||
|
context=bridge2-from-pbx
|
||||||
|
|
||||||
|
[bridge2-pbx-auth]
|
||||||
|
type=auth
|
||||||
|
auth_type=userpass
|
||||||
|
username=bridge2-pbx
|
||||||
|
password=BRIDGE2_SIP_SECRET
|
||||||
|
|
||||||
|
[bridge2-pbx]
|
||||||
|
type=aor
|
||||||
|
max_contacts=1
|
||||||
|
remove_existing=yes
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Additional bridges — copy this triple and increment N
|
||||||
|
; ============================================================
|
||||||
|
;[bridge3-pbx](bridge-endpoint-tmpl)
|
||||||
|
;type=endpoint
|
||||||
|
;auth=bridge3-pbx-auth
|
||||||
|
;aors=bridge3-pbx
|
||||||
|
;context=bridge3-from-pbx
|
||||||
|
;
|
||||||
|
;[bridge3-pbx-auth]
|
||||||
|
;type=auth
|
||||||
|
;auth_type=userpass
|
||||||
|
;username=bridge3-pbx
|
||||||
|
;password=BRIDGE3_SIP_SECRET
|
||||||
|
;
|
||||||
|
;[bridge3-pbx]
|
||||||
|
;type=aor
|
||||||
|
;max_contacts=1
|
||||||
|
;remove_existing=yes
|
||||||
74
acSipBridge/sip.conf
Normal file
74
acSipBridge/sip.conf
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
; ============================================================
|
||||||
|
; AstroCom SIP Bridge — SIP Configuration (chan_sip)
|
||||||
|
; /etc/asterisk/sip.conf
|
||||||
|
;
|
||||||
|
; Downstream PBXes REGISTER to this server.
|
||||||
|
; Each bridge has one [bridgeN-pbx] peer with host=dynamic.
|
||||||
|
;
|
||||||
|
; The PBX must be configured to register with:
|
||||||
|
; Registrar : <this server's IP>:5060
|
||||||
|
; Username : bridgeN-pbx (the section name below)
|
||||||
|
; Password : the 'secret' value below
|
||||||
|
;
|
||||||
|
; 'context' is where calls FROM the PBX land (outbound to AstroCom).
|
||||||
|
; It must match [bridgeN-from-pbx] in extensions.conf.
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
[general]
|
||||||
|
bindport=5060
|
||||||
|
bindaddr=0.0.0.0
|
||||||
|
realm=ac-sip-bridge
|
||||||
|
srvlookup=no
|
||||||
|
; NAT handling — set to 'force_rport,comedia' if PBX is behind NAT
|
||||||
|
nat=no
|
||||||
|
qualify=no
|
||||||
|
disallow=all
|
||||||
|
allow=ulaw
|
||||||
|
allow=alaw
|
||||||
|
allow=g729
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Shared peer template
|
||||||
|
; ============================================================
|
||||||
|
[bridge-sip-tmpl](!)
|
||||||
|
type=friend
|
||||||
|
host=dynamic ; IP is learned from the REGISTER request
|
||||||
|
dtmfmode=rfc2833
|
||||||
|
canreinvite=no
|
||||||
|
disallow=all
|
||||||
|
allow=ulaw
|
||||||
|
allow=alaw
|
||||||
|
allow=g729
|
||||||
|
qualify=yes
|
||||||
|
; No 'insecure=' — registration provides proper authentication.
|
||||||
|
; Removing it means unauthenticated INVITEs from unknown IPs are rejected.
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 1
|
||||||
|
; PBX registers as username 'bridge1-pbx' with the secret below.
|
||||||
|
; Outbound to this PBX: Dial(SIP/bridge1-pbx/<exten>)
|
||||||
|
; → delivered to the registered contact URI.
|
||||||
|
; ============================================================
|
||||||
|
[bridge1-pbx](bridge-sip-tmpl)
|
||||||
|
secret=1242ebce8b420ee4723887ffe0a01211330851776862e6021f680f1406c94eff
|
||||||
|
; If the PBX must register with a different username, set it here:
|
||||||
|
;username=bridge1
|
||||||
|
fromuser=bridge1-pbx ; identity used in outbound SIP From: headers
|
||||||
|
context=bridge1-from-pbx
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; BRIDGE 2
|
||||||
|
; PBX registers as username 'bridge2-pbx' with the secret below.
|
||||||
|
; ============================================================
|
||||||
|
[bridge2-pbx](bridge-sip-tmpl)
|
||||||
|
secret=BRIDGE2_SIP_SECRET
|
||||||
|
fromuser=bridge2-pbx
|
||||||
|
context=bridge2-from-pbx
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; Additional bridges — copy this block and increment N
|
||||||
|
; ============================================================
|
||||||
|
;[bridge3-pbx](bridge-sip-tmpl)
|
||||||
|
;secret=BRIDGE3_SIP_SECRET
|
||||||
|
;fromuser=bridge3-pbx
|
||||||
|
;context=bridge3-from-pbx
|
||||||
157
acSipBridge/theory.md
Normal file
157
acSipBridge/theory.md
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
# AstroCom SIP Bridge — Design Notes
|
||||||
|
|
||||||
|
This directory contains a set of Asterisk configuration files that act as a
|
||||||
|
**protocol bridge** between IAX2 (used by AstroCom) and SIP (used by
|
||||||
|
downstream, non-Asterisk phone systems such as FreeSWITCH, 3CX, Cisco
|
||||||
|
UCM, or any generic SIP PBX).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `iax.conf` | IAX2 peers — one per bridge, pointing at AstroCom |
|
||||||
|
| `pjsip.conf` | PJSIP endpoints — one triple (endpoint/auth/aor) per bridge |
|
||||||
|
| `extensions.conf` | Dialplan — contexts that wire IAX↔PJSIP for each bridge |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ AstroCom Platform │
|
||||||
|
│ (IAX2 server, routes DB) │
|
||||||
|
└──────────┬──────────────────────-┘
|
||||||
|
│ IAX2 (port 4569)
|
||||||
|
┌───────────────┼────────────────┐
|
||||||
|
│ │ │
|
||||||
|
IAX2 peer IAX2 peer IAX2 peer
|
||||||
|
bridge1-astrocom bridge2-astrocom bridgeN-astrocom
|
||||||
|
│ │ │
|
||||||
|
┌───────┴───────────────┴────────────────┴──────┐
|
||||||
|
│ Bridge Server │
|
||||||
|
│ (this Asterisk instance) │
|
||||||
|
│ │
|
||||||
|
│ [bridge1-from-astrocom] [bridge1-from-pbx] │
|
||||||
|
│ [bridge2-from-astrocom] [bridge2-from-pbx] │
|
||||||
|
│ [bridgeN-from-astrocom] [bridgeN-from-pbx] │
|
||||||
|
└───────┬───────────────┬────────────────┬──────┘
|
||||||
|
│ │ │
|
||||||
|
SIP peer SIP peer SIP peer
|
||||||
|
bridge1-pbx bridge2-pbx bridgeN-pbx
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
PBX / System 1 PBX / System 2 PBX / System N
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inbound call (AstroCom → PBX)
|
||||||
|
|
||||||
|
1. AstroCom looks up the dialled number in its `routes` table and finds
|
||||||
|
the bridge server's IP (`routes.server`) and port (`routes.port`).
|
||||||
|
2. AstroCom dials over IAX2 using the shared secret (`routes.secret`)
|
||||||
|
and delivers the call to the context named in `routes.auth`
|
||||||
|
(e.g. `bridge1-from-astrocom`).
|
||||||
|
3. The bridge's dialplan receives the call in `[bridge1-from-astrocom]`
|
||||||
|
and dials `SIP/bridge1-pbx/<EXTEN>`. Because the PBX has already
|
||||||
|
registered (`host=dynamic`), Asterisk knows the current contact URI
|
||||||
|
and sends the INVITE directly to it.
|
||||||
|
|
||||||
|
### Outbound call (PBX → AstroCom)
|
||||||
|
|
||||||
|
1. The downstream PBX has registered to this server as `bridge1-pbx`.
|
||||||
|
It sends a SIP INVITE for the target number.
|
||||||
|
2. `sip.conf` authenticates the REGISTER/INVITE against `secret` and
|
||||||
|
lands the call in context `bridge1-from-pbx`.
|
||||||
|
3. The dialplan CURLs the AstroCom routing API:
|
||||||
|
`GET /api/v1/route/<apiKey>/<ANI>/<number>`
|
||||||
|
4. The API returns either `"local"` (callee is on the same PBX — route
|
||||||
|
back via `SIP/bridge1-pbx/<exten>`) or a full
|
||||||
|
`IAX2/<auth>:<secret>@<host>:<port>/<number>` URI which is dialled
|
||||||
|
verbatim.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AstroCom Database Requirements
|
||||||
|
|
||||||
|
For each bridge you must create one row in the `routes` table:
|
||||||
|
|
||||||
|
| Column | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| `server` | Bridge server's public IP |
|
||||||
|
| `port` | `4569` (IAX2) |
|
||||||
|
| `auth` | `bridgeN-from-astrocom` (must match context name) |
|
||||||
|
| `secret` | The shared IAX2 secret (`BRIDGEN_IAX_SECRET`) |
|
||||||
|
| `block_start` | First number in this bridge's number block |
|
||||||
|
| `block_length` | Size of the block (default 9999) |
|
||||||
|
| `apiKey` | Auto-generated by AstroCom on creation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Isolation Model
|
||||||
|
|
||||||
|
Each bridge is **completely isolated** by default:
|
||||||
|
|
||||||
|
- IAX2 peers use separate contexts (`bridge1-from-astrocom`, etc.)
|
||||||
|
- PJSIP endpoints use separate contexts (`bridge1-from-pbx`, etc.)
|
||||||
|
- No context includes or jumps to another bridge's context
|
||||||
|
- The `[default]` context drops all unmatched calls
|
||||||
|
|
||||||
|
### Calling between bridges
|
||||||
|
|
||||||
|
Calls between Bridge-1 and Bridge-2 work through AstroCom's normal
|
||||||
|
routing — Bridge-1's PBX dials a number, it travels to AstroCom via
|
||||||
|
IAX2, AstroCom routes it to Bridge-2's context, and it arrives at
|
||||||
|
Bridge-2's PBX via PJSIP. **No special config is needed for this.**
|
||||||
|
|
||||||
|
If you want **direct PJSIP** bridging (bypassing AstroCom for inter-bridge
|
||||||
|
calls), see the commented-out section at the bottom of `extensions.conf`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a New Bridge
|
||||||
|
|
||||||
|
1. **`iax.conf`** — Copy the `[bridge1-from-astrocom]` block, rename it to
|
||||||
|
`[bridgeN-from-astrocom]`, and set a new `secret` and `context`.
|
||||||
|
|
||||||
|
2. **`pjsip.conf`** — Copy the three stanzas for `bridge1-pbx`, rename them
|
||||||
|
to `bridgeN-pbx` / `bridgeN-pbx-auth`, set a new `password`, and update
|
||||||
|
`context`. The downstream PBX must be configured to register with:
|
||||||
|
- **Registrar**: `sip:<bridge server IP>:5060`
|
||||||
|
- **Username**: `bridgeN-pbx`
|
||||||
|
- **Password**: the `password` value in `[bridgeN-pbx-auth]`
|
||||||
|
|
||||||
|
3. **`extensions.conf`** — Copy both the `[bridge1-from-astrocom]` and
|
||||||
|
`[bridge1-from-pbx]` context blocks, rename them to
|
||||||
|
`[bridgeN-from-astrocom]` / `[bridgeN-from-pbx]`, and update the
|
||||||
|
`Dial()` targets and global variable names.
|
||||||
|
Add `BRIDGEN_APIKEY` and `BRIDGEN_EXCHANGE` to `globals.conf`.
|
||||||
|
|
||||||
|
4. **AstroCom** — Create the route via the admin panel or API with
|
||||||
|
`auth = bridgeN-from-astrocom` and the matching `secret`.
|
||||||
|
|
||||||
|
5. Reload Asterisk:
|
||||||
|
```
|
||||||
|
asterisk -rx "pjsip reload"
|
||||||
|
asterisk -rx "iax2 reload"
|
||||||
|
asterisk -rx "dialplan reload"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Codecs**: `ulaw`, `alaw`, and `g729` are negotiated; adjust per your
|
||||||
|
network and licensing constraints.
|
||||||
|
- **NAT**: If a downstream PBX is behind NAT, set `direct_media=no` (already
|
||||||
|
in the template) and add `local_net` / `external_signaling_address` /
|
||||||
|
`external_media_address` to `[bridge-transport]` in `pjsip.conf`.
|
||||||
|
- **No `register =>`** for IAX2: IP updates use `tools/astrocom_dynamic_ip.sh`
|
||||||
|
or the `/api/v1/user/update` API endpoint — not IAX2 registration.
|
||||||
|
- **Security**: Each bridge's IAX2 secret should be a long random string
|
||||||
|
(AstroCom generates one via `crypto.randomBytes(15).toString('hex')`
|
||||||
|
if none is specified during route creation).
|
||||||
|
- **`sip.conf`**: The old `chan_sip` config is superseded by `pjsip.conf`.
|
||||||
|
Ensure `chan_sip` is not loaded (`noload => chan_sip.so` in `modules.conf`)
|
||||||
|
to avoid both modules fighting over port 5060.
|
||||||
Loading…
Reference in a new issue