* [core] Add interface allowlist to gate module app/api registration
Adds an optional, presence-activated allowlist in switch.conf.xml that
controls which modules may register application / api / json_api /
chat-application interfaces. With no <interface-allowlist> configured
nothing is enforced; when at least one <allow> entry is present, only
listed interfaces register at load time and all others are refused (the
module still loads and switch_loadable_module_process still returns
SUCCESS -- the blocked interface is simply never exposed).
Entries match at three levels of precision:
mod_commands - whole module
mod_commands.system - any interface named "system"
mod_commands.system.api - a specific type (app|api|json_api|chat_app)
Enforcement lives in switch_loadable_module_process() so every module, at
boot and at runtime `load`, is subject to the same policy. This gives
operators a way to disable the "system"/"spawn" shell-exec API commands
(and equivalents) system-wide.
Also adds the `interface_allowlist_dump [modules] [plain]` API, which
walks the loaded modules and prints their interfaces in the allowlist key
format so the current state can be captured and pruned offline into config.
* [mod_commands] Add tests for the interface allowlist
New test_interface_allowlist boots the core with an active
<interface-allowlist> (conf_interface_allowlist/) that permits only a
couple of mod_commands interfaces, then loads mod_commands and verifies:
- listed commands register and run (status, version) while unlisted and
shell-exec commands are refused (system, spawn, uptime) -- refusal
surfaces as switch_api_execute returning FALSE / command-not-found,
with the command function never invoked;
- a "module.name.type" entry gates by type: the API "status" loads while
the JSON API of the same name stays blocked;
- interface_allowlist_dump prints the config format in its xml, modules
and plain variants, and reflects module capabilities (system appears in
the dump even though it was blocked from registering).
* [config] Fix interior -- in interface-allowlist comment breaking XML parse
The explanatory comment used -- as em-dash pairs. The XML parser treats
-- inside a comment as the comment close, causing an "unclosed <!--"
error that prevents the whole freeswitch.xml from parsing (boot and
reloadxml both fail). Replace the -- pairs with ordinary punctuation.
* update .gitignore
* [core] Warn when interface-allowlist section is present but parses no entries
When a command response publish failed, `mod_amqp_command_response` closed
the connection and cleared conn_active. The command thread teardown then
called mod_amqp_connection_close(NULL), causing a segfault.
Also fix amqp_error_string2() calls to pass status codes without erroneous negation.
A swig 4.1 regeneration dropped several hand-patched wrapper edits.
Express them (and the rest) as SWIG typemaps in `freeswitch.i` so they
survive reswig. `make reswig` now produces the final wrapper directly;
`hack.diff` and its `patch` step are removed.
Restored regressions:
- `setLUA(L)` on returned `Session`: a hangup hook or input callback on
a script-created `freeswitch.Session()` no longer crashes the process
- binary-safe `Stream::read` (`lua_pushlstring`)
Also moved to typemaps:
- `Dbh`/`JSON` self-pointer guards (`%typemap(check)`), now covering
every wrapper including four the hand-patch missed
- type-table isolation (`#define SWIG_TYPE_TABLE mod_lua`)
* [libesl] Validate `Content-Length` in `esl_recv_event`.
`atol()` accepted negative values, allowing a remote ESL peer to cause
a one-byte heap underwrite (`Content-Length: -1`) or NULL-pointer
dereference (`Content-Length: -2`, since `esl_assert` compiles out
under `NDEBUG`). Reject negative and oversized values, and check
`malloc` failure instead of relying on `assert`.
Cap at `ESL_MAX_CONTENT_LENGTH` (16 MiB).
* [libesl] Add test_recv_event.
Lower `CJSON_NESTING_LIMIT` from upstream default 1000 to 64 via
`SWITCH_AM_CFLAGS` / `SWITCH_AM_CXXFLAGS`. The mutually recursive
`parse_value`/`parse_array`/`parse_object` chain in cJSON consumes
~2 stack frames per nesting level, which can overflow worker
threads running on `SWITCH_THREAD_STACKSIZE` (240 KB).
In `check_auth()` the userauth branch committed request `userVariables`,
`JPFLAG_RESUME_CALL`, identity fields, `<user><params>`/`<variables>`,
`dialplan`, and `context` to `jsock` *before* the password compare. On
mismatch only `jsock->uid` was reverted; the rest persisted on the
socket and leaked into outbound/inbound INVITE setup and `jsapi`/event
publishes.
Restructure so the gate runs first: pre-scan `<user><params>` into
locals, compare, and on mismatch return FALSE with no `jsock` writes.
Identity/vars commits and `<user><params>`/`<variables>` persistence
move past the gate. Blind-reg short-circuit and
`req_params`/`x_user` ownership preserved on every exit; success-path
writes are bit-for-bit equivalent.
Side cleanups:
- "Login sucessful" → "Login successful" typo;
- success log WARNING → NOTICE;
- the spurious WARNING "Login sucessful" no longer fires on bad-password
attempts that located the user in the directory;
`process_jrpc()` called `set_session_id()` before `check_auth()`, so an
unauthenticated client could insert its jsock into `jsock_hash` under a
foreign `sessid` and have `attach_jsock()` evict the prior owner
(`verto.punt` + `detach_calls()` + `drop=1`) with no identity check.
Move the bind past the auth gate; `JPFLAG_INIT` now means "jsock is
bound", not "first frame seen". Additionally, `attach_jsock()` refuses
the bind when prior and new jsock are authed under different `uid`s,
replying `CODE_AUTH_FAILED` "Session in use". Same-uid reconnect and
no-auth profile binds are unchanged.
Unchecked `atoi()` on declared payload size let a client
request up to `INT_MAX`, forcing the server to write ~20 GB
per request via the download phase. Short `#` frames also
triggered OOB reads on `s[1..3]`.
- Gate `#` branch on `JPFLAG_AUTHED`.
- Cap declared size at 10 MiB (`VERTO_SPEED_TEST_MAX_SIZE`).
- Replace `atoi()` with bounded `strtol()`.
- Require `bytes >= 4` before indexing `s[1..3]`.
Cap `Content-Length` at `HTTP_POST_MAX_BODY` (10 MiB) and size the
allocation to the actual body length (`content_length + 1` for
the trailing NUL).
Also fix `WS_BLOCK` units — `kws_raw_read` takes ms, set to 10000.
ffmpeg@5 changed to ffmpeg@7
Note: tested ffmpeg@8 but it causes missing ft2build.h in truetype include library.
libpq@16 changed to libpq@18
Co-authored-by: Andrey Volk <andywolk@gmail.com>
Route IPv6 writes in `switch_stun_packet_attribute_add_binded_address`
and `switch_stun_packet_attribute_add_xor_binded_address` through
`switch_stun_ipv6_t` (16-byte `address[]`) instead of `switch_stun_ip_t`
(4-byte `uint32_t address`).
Add IPv4/IPv6 unit tests for both encoders.
Co-authored-by: Andrey Volk <andywolk@gmail.com>
Implement SIP 603+ (ATIS-1000099) support for FCC analytics-based call blocking compliance.
Detection:
- Detect incoming 603+ responses by checking "Network Blocked" phrase
and "v=analytics1;" in the `Reason` header text
- Set `sip_603plus_reason` channel variable on both legs for CDR visibility
Passthrough control:
- `sip_603plus_passthrough=true`: forward 603+ phrase and Reason header
- `sip_603plus_passthrough=false`: strip `Reason` header, send clean `603 Decline`
- Not set: existing behavior preserved
- Works independently of `disable_q850_reason` for selective forwarding