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