150 Commits
Author SHA1 Message Date
Dmitry Verenitsin 2c8802e64b [core] Validate IPv6 XOR-MAPPED-ADDRESS length in STUN parser (#3115)
`switch_stun_packet_attribute_get_xor_mapped_address()` read and
XOR-rewrote a 16-byte IPv6 address whenever the `family` byte was 2,
without checking the attribute value was that long. Reject `family == 2`
values shorter than `sizeof(switch_stun_ipv6_t)` and clear the output
address and port. Adds a regression test.
2026-08-08 23:39:40 +03:00
Dmitry Verenitsin 03485e1f4c [core] Harden STUN attribute parsing bounds and USERNAME copy (#3112)
Bounds and termination fixes across the STUN attribute receive path
in `handle_ice` and `switch_stun_lookup`:

- `switch_stun_packet_next_attribute` and its `_hbo` variant now
  confirm the 4-byte attribute header is fully within `end` before
  dereferencing `type`/`length`, and include the header when checking
  that the value fits, so a truncated or overrunning attribute is not
  read past the buffer.
- Compute `end_buf` as the 20-byte STUN header plus the attribute
  section (`SWITCH_STUN_PACKET_MIN_LEN + header.length`) so the walk
  covers every attribute, including trailing ones.
- Make `switch_stun_packet_next_attribute` the sole loop terminator
  and drop the redundant `xlen` guard; its seed differed between the
  two functions and could skip a trailing attribute in
  `switch_stun_lookup`.
- `switch_stun_packet_attribute_get_username` reserves a byte for the
  terminator and always NUL-terminates, since callers use the result
  as a C string.
2026-08-08 22:33:58 +03:00
Dmitry Verenitsin 3630e3dd85 [core] Harden switch_b64_encode output bound (#3111)
switch_b64_encode wrote each base64 character before checking the
output bound, and computed that bound as `bytes >= (int)olen - 1`.
Both are unsafe:

- Writing before the check meant a buffer with no room for a data
  byte still received one: `olen == 1` wrote a character at index 0
  and the NUL at index 1, and `olen == 0` (where `(int)olen - 1` is
  -1) wrote two bytes, both past the end.
- Casting the unsigned `olen` to `int` truncated it above INT_MAX,
  producing a wrong bound for very large buffers.

Reject `olen == 0`, make the output index `bytes` a `size_t`, and test
`bytes + 1 >= olen` before each write, so the bound never casts or
underflows and always leaves the last byte for the terminator. Apply
the same `bytes + 1 < olen` guard to the trailing partial-group
character and the `=` padding, so no write can pass the end.

Remove the dead line-wrap counter `y`: it only gated a commented-out
newline emit, so it counted and reset with no effect on the output.

Add unit tests covering the output-bound edges for every write site.
2026-08-08 22:05:20 +03:00
Dmitry Verenitsin 394b48b9f5 [core] Harden switch_b64_decode output bound and input handling (#3110)
switch_b64_decode bounded its writes with `ol >= olen - 1`, where
`olen` is unsigned. An `olen` of 0 made `olen - 1` wrap to `SIZE_MAX`,
so the bound never fired and the loop wrote the entire decoded input
plus a trailing NUL past the destination. Reject `olen == 0` and test
`ol + 1 >= olen` before each write, so the comparison never subtracts
from an unsigned and always leaves room for the terminator.

The alphabet lookup table `l64` was a `char` indexed by a `char`,
which is unsafe whichever way `char` is signed:

- Where `char` is signed, an input byte >= 0x80 became a negative
  index and read before the table.
- Where `char` is unsigned, the `-1` "not in alphabet" sentinel was
  stored as 255, so the skip test never matched and non-alphabet
  bytes were folded in as data.

Make `l64` a `signed char` and index it with `(unsigned char)`, so the
sentinel survives and the index stays in range on every platform.

Change the bit accumulator `b` from `int` to `unsigned int` to avoid
signed-overflow undefined behavior on long input; decoded output is
unchanged.

Add unit tests: an encode/decode round-trip across the padding cases,
the output-bound edges (`olen` of 0, 1, and a truncating buffer), and
a non-alphabet byte (including one >= 0x80) that must be skipped.
2026-08-08 21:40:30 +03:00
Dmitry Verenitsin 28fcfd2624 Merge commit from fork
* Merge commit from fork

* [core] Fix XML escape encoder overrun and unsigned-char UTF-8 gate

`switch_xml_ampencode()` had two independent defects in its UTF-8
numeric-escape path.

Buffer overrun: the encoder grows its destination once per source byte,
but the realloc margin reserved only the 10 data characters of the
widest escape `"&#x%X;"` (a 21-bit code point rendered as 6 hex digits),
not the terminating NUL that `sprintf` also writes. At the margin
boundary that NUL landed one byte past the allocation. Reserve 11 bytes
in the guard (10 data chars plus the NUL) and emit the escape with
`snprintf` bounded to the remaining space, so the write stays in bounds
even if the margin is ever miscounted. The other escape sinks are all
within the widened margin and are unchanged.

Char signedness: the lead-byte test `(*s >> 8) & 0x01` reads bit 8 of a
plain `char`, which exists only after sign extension. Where `char` is
signed the high bit sign-extends and the test passes; where `char` is
unsigned it is always zero, so the numeric-escape path never ran and
multi-byte UTF-8 was emitted raw, making serialized XML differ by
architecture. Test bit 7 directly with `(*s & 0x80)`, correct regardless
of `char` signedness. This also makes the overrun fix effective on
unsigned-`char` builds, where the escape path now runs.

Add unit test `test_utf_8_wide_codepoint`, which serializes U+10FFFF and
long runs of it across buffer reallocations, sweeping an ASCII prefix so
an escape is emitted at the minimum-headroom offset, and asserts the
full serialized length.
2026-08-08 21:02:15 +03:00
Dmitry Verenitsin 86b10358e2 Merge commit from fork
`switch_core_media_add_crypto()` parses the SDP `a=crypto` keysalt and
decodes it into a fixed-size key buffer. Enforce the buffer contract at
the call site:

- Reject a zero-length, negative, or over-long keysalt (the length
  check now has both a lower bound and an upper bound against the copy
  buffer).
- Copy the keysalt token into a NUL-terminated buffer and decode from
  that, so `switch_b64_decode` stops at the token instead of reading on
  into the following key material (it consumes input to the NUL and
  skips non-base64 bytes).
- Pass the destination buffer size as the decode bound rather than the
  parsed token length.
- Require the decoded length to cover the crypto suite's key+salt so the
  subsequent copy cannot read past the decoded bytes.

Add `test_add_crypto_keysalt_bounds`, a table-driven test covering the
accepted and rejected keysalt shapes across suites (AES-128/192/256),
including RFC 4568 lifetime/MKI and multi-key lines.
2026-08-08 19:47:47 +03:00
Dmitry Verenitsin 6f47b5c38c [unit-tests] Bind the DTLS certificate test on the configured RTP port (#3108) 2026-08-08 19:46:34 +03:00
Dmitry Verenitsin e730a4e541 Merge commit from fork
The RTCP NACK feedback handler used the packet's header length field as the
loop bound instead of the byte count the caller already validated. An
oversized length ran the loop past the fixed-size RTCP buffer, an
out-of-bounds access.

Clamp the entry count to the feedback words that fit in the received packet.

Add an end-to-end test feeding an oversized-length NACK through the RTCP
reader.
2026-08-08 18:29:25 +03:00
Dmitry Verenitsin 30cdb387ae Merge commit from fork
The positive-offset branch of `${variable:offset}` expansion advanced
`sub_val` past the cloned heap buffer without bounds-checking `offset`
against `strlen(sub_val)`. Subsequent `strlen()` and `strcat()` then
read adjacent heap memory into the output buffer.
2026-08-08 18:18:50 +03:00
ea74c0acb8 Merge commit from fork
* [Core, mod_commands] Interface allowlist (#3086)

* [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

Co-authored-by: Chris Rienzo <chris@signalwire.com>

* Merge commit from fork

Add `switch_stun_packet_verify_integrity()`, an HMAC-SHA1
MESSAGE-INTEGRITY verifier that is const and non-mutating: it runs
over a private copy of the pristine network-order packet, so the
caller's buffer and byte order stay untouched, and walks attributes
with its own unsigned bounded helper `stun_wire_attr_bounds()`
instead of the host-order iterator macros. A trailing
MESSAGE-INTEGRITY-SHA256 or FINGERPRINT after MESSAGE-INTEGRITY is
tolerated; any other trailing attribute is rejected.

Gate it in `handle_ice()` behind `ice->verify_integrity`: verify
before any ICE state is touched, keyed by message type (local
`ice->pass` for a request, remote `ice->rpass` for a response or
error response), and drop on failure. Keepalive indications carry no
MESSAGE-INTEGRITY and are ignored.

`ice->verify_integrity` is read from the `ice_verify_message_integrity`
channel variable in `switch_rtp_activate_ice()` and defaults off, so
receive-path behavior is unchanged unless it is enabled. Adds unit
tests in `tests/unit/switch_stun.c`.

* Merge commit from fork

* [core] Verify DTLS client cert against SDP fingerprint (server role)

Add opt-in verification of the client certificate when FreeSWITCH is
the DTLS server, mirroring the binding the client role already performs
on the server certificate: match the peer certificate against the SDP
`a=fingerprint` in `dtls_state_setup()`.

Selected per call by the `rtp_dtls_client_cert_verify_mode` channel
variable (`dtls_client_cert_verify_t`). An unset variable keeps the
default `DTLS_CLIENT_CERT_VERIFY_NONE`, so existing behavior is
unchanged:

- `none`: the server does not request a client certificate.
- `fingerprint`: request it (`SSL_VERIFY_PEER` + `dtls_accept_any_cert`)
  and require its fingerprint to match the SDP value; a self-signed
  certificate is accepted at the TLS layer and the match provides
  authenticity.
- `full`: additionally let OpenSSL enforce the certificate chain.

An unrecognized mode string falls back to `fingerprint` (fail closed)
with a warning.

The mode is set per `SSL` object in `switch_rtp_add_dtls()`. Verification
fails (`DS_FAIL`, no SRTP keys derived) when the client presents no
certificate, its fingerprint does not match, or the peer advertised no
usable `a=fingerprint`: `get_evp_by_name()` returns `NULL` for a missing
or empty hash type and `switch_core_cert_extract_fingerprint()` rejects a
`NULL` algorithm rather than passing it to `X509_digest()`.

`conf/vanilla/vars.xml` documents the knob as a disabled example. Tests
in `tests/unit/switch_rtp.c` cover matching, mismatched, absent-cert,
absent-fingerprint, `none`, and unrecognized-mode cases.

---------

Co-authored-by: Andrey Volk <andywolk@gmail.com>
Co-authored-by: Chris Rienzo <chris@signalwire.com>
2026-08-08 18:14:08 +03:00
Dmitry Verenitsin a097e12421 Merge commit from fork
`read_packet()` passed a peer-supplied `Content-Length` straight to
`switch_zmalloc(body, clen + 1)`. Huge values drove `calloc` failure
and `switch_zmalloc` `abort()`-ed the daemon.

- Cap `Content-Length` at 16 MiB; reject negatives.
- Destroy the partially-built `*event` at the new rejection site and
at the existing body-recv failure path so callers don't leak it.
- Add `test_mod_event_socket` covering `INT_MAX`, above-cap,
negative, `atoi`-overflow, zero, and valid-non-zero-body cases.
2026-08-08 17:48:05 +03:00
Dmitry Verenitsin 587474a158 Merge commit from fork 2026-08-08 17:07:32 +03:00
Dmitry Verenitsin 68ec688eb6 Merge commit from fork
Add `switch_stun_packet_verify_integrity()`, an HMAC-SHA1
MESSAGE-INTEGRITY verifier that is const and non-mutating: it runs
over a private copy of the pristine network-order packet, so the
caller's buffer and byte order stay untouched, and walks attributes
with its own unsigned bounded helper `stun_wire_attr_bounds()`
instead of the host-order iterator macros. A trailing
MESSAGE-INTEGRITY-SHA256 or FINGERPRINT after MESSAGE-INTEGRITY is
tolerated; any other trailing attribute is rejected.

Gate it in `handle_ice()` behind `ice->verify_integrity`: verify
before any ICE state is touched, keyed by message type (local
`ice->pass` for a request, remote `ice->rpass` for a response or
error response), and drop on failure. Keepalive indications carry no
MESSAGE-INTEGRITY and are ignored.

`ice->verify_integrity` is read from the `ice_verify_message_integrity`
channel variable in `switch_rtp_activate_ice()` and defaults off, so
receive-path behavior is unchanged unless it is enabled. Adds unit
tests in `tests/unit/switch_stun.c`.
2026-08-08 17:03:47 +03:00
Andrey Volk be554e4a08 [Core] switch_sockaddr_info_get() will not resolve if the hostname is an IP address. Add new switch_is_ip_address() API. Add a unit-test. (#3055) 2026-06-12 16:13:47 +03:00
Dmitry Verenitsin 33ee3663bb Merge commit from fork
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.
2026-05-26 22:02:42 +03:00
Dmitry VerenitsinandAndrey Volk bf9c95e890 [core] Use switch_stun_ipv6_t for STUN IPv6 write paths. (#3037)
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>
2026-05-26 18:11:11 +03:00
Dmitry Verenitsin 325bb3a606 [core] Fix segments count check in clean_uri(). Add unit-test. (#3032) 2026-05-26 00:16:40 +03:00
Andrey Volk 2a7100053a Merge commit from fork 2026-05-07 20:18:11 +03:00
Andrey VolkandJakub Karolczyk ce12717ad7 Merge commit from fork
Co-authored-by: Jakub Karolczyk <jakub.karolczyk@signalwire.com>
2026-05-07 20:14:34 +03:00
Seven Du 7f9dd270b4 [core] add uuidv7 support 2025-07-31 19:38:54 +03:00
Andrey Volk 65bc7c14bf [Core] Upgrade FreeSWITCH to use PCRE2 library. Be aware of breaking changes. 2025-07-15 18:26:17 +03:00
Andrey Volk 68e587d7cf [Unit-tests] Fix test framework error on newer compiler: 'strncpy' output truncated before terminating nul copying as many bytes from a string as its length [-Werror=stringop-truncation] 2025-07-10 19:15:31 +03:00
Andrey Volk 10d31ee12a [Unit-tests] Move test_tts_format out of mod_ssml. Add mod_test and test_tts_format to the Windows build. 2024-12-31 01:45:47 +03:00
s3rj1k 556702ce9f [GHA] Refactor workflows 2024-12-03 21:30:46 +01:00
Andrey Volk 8e694fe10b [Build-System] Upgrade legacy Windows SDK to 10.0 in Visual Studio projects. 2024-12-03 22:59:02 +03:00
s3rj1k 07283ac104 [GHA] Add tests. 2024-10-11 20:16:39 +02:00
Seven Du ef3bd2d8c3 [core] fix base64 decoded size when encoded string contains padding = 2024-10-09 22:53:00 +08:00
Andrey Volk c7e793c345 [Core] Add new switch_rand() a compliant random number generator API. Add a unit-test.
* [Core] Add new switch_rand() a compliant random number generator API. Add a unit-test.

* Fall back to rand() on unsupported platforms compile time.
2024-06-06 21:14:36 +03:00
Andrey Volk 5b1c2688da [Core, mod_sofia] Add switch_uint31_t type. Fix CSeq bigger than 2^31-1. 2024-05-09 22:20:14 +03:00
Andrey Volk 647035c323 [mod_opus] Fix status returned by switch_opus_decode(). Should be SWITCH_STATUS_FALSE instead of SWITCH_STATUS_NOOP. Add a unit-test. 2024-02-06 00:36:35 +03:00
Dragos Oancea 8b7a8c4aea [core] SDP: replace SIP lingo in SDP offer/answer. 2024-01-26 21:01:32 +03:00
Andrey Volk d08424384b [Core] Coverity: 1024552 Logically dead code 2023-10-05 18:03:32 +03:00
Andrey Volk 9347c96712 [Core] check_ice: sanitize second field of the candidates. Add new switch_is_uint_in_range() API. 2023-08-13 15:49:58 +03:00
Andrey Volk 6b67970bbb [Core] Add new switch_channel_get_variable_strdup() and switch_channel_get_variable_buf() APIs that avoid allocating channel variables in a session's memory pool. 2023-07-28 22:29:22 +03:00
Jakub Karolczyk 930341ba86 [core,mod_av,unit-tests] Make transition to core packetizer 2023-07-10 12:58:19 +00:00
Andrey Volk b2e78c90e7 [Build-System] Fix MD5 on Windows. Add a unit-test. 2023-01-18 02:55:34 +03:00
Andrey Volk f71a56022a [Core] switch_mprintf: Increase the size of loop variables in the printf() implementation. Add unit-tests disabled by default. 2022-12-09 23:11:25 +03:00
Dragos Oancea 8e59603d98 [core][mod_sofia] remove ZRTP (deemed obsolete).
[unit-tests][build-system][docs] remove references to ZRTP.
2022-10-28 20:19:42 +03:00
Andrey Volk 23eeb4ae75 [Unit-tests] Improve stability of some tests. 2022-08-28 13:24:43 +03:00
Andrey Volk d38ed7d379 [Unit-tests] Fix unused function in switch_rtp_pcap 2022-06-29 21:42:37 +03:00
Dragos Oancea beffab1d68 [core] RTP: a media timeout fix + add pcap based-unit tests. 2022-06-29 18:20:27 +03:00
Andrey Volk fbf2da44d9 [Core] Fix use of private headers. 2021-11-10 21:46:29 +03:00
Andrey Volk 0fdd5b6727 [Core] Fix switch_event_base_add_header leaking memory when headers are with indexes. Add a unit-test.
* [Unit-tests] Add a test provoking switch_event_add_header to memory leak.
* [Core] Fix switch_event_base_add_header leaking memory when headers are with indexes.
2021-11-03 17:01:05 +03:00
Sebastian Kemper a2ce46c6fd [core] fix "--disable-libyuv"
Recent changes made it impossible to compile freeswitch without libyuv
support.

src/switch_core_video.c: In function 'switch_img_read_from_file':
src/switch_core_video.c:3139:4: error: implicit declaration of function 'RAWToI420' [-Werror=implicit-function-declaration]
RAWToI420(data, width * 3,
^
src/switch_core_video.c:3148:4: error: implicit declaration of function 'ABGRToARGB' [-Werror=implicit-function-declaration]
ABGRToARGB(data, width * 4, img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], width, height);
^

Fix this my adding/moving the checks for "SWITCH_HAVE_YUV".

Signed-off-by: Sebastian Kemper <sebastian_ml@gmx.net>
2021-11-01 19:35:53 +03:00
Seven Du 408480bae0 [Unit-tests] Fix mac build
* [core] fix build err on Mac
* [mod_av] fix build on macOS
2021-10-24 15:36:52 +03:00
Andrey Volk bf62bd8a7f [Unit-test] Use unique port numbers when running mod_sofia tests. 2021-10-23 22:01:16 +03:00
Andrey Volk 24ff01518f [Unit-tests] Fix build of various unit-tests. 2021-10-23 22:01:08 +03:00
dhruvecosmob 715f9e4d28 [Unit-tests] Add a unit-test for the compact form and full form of the Identity header. 2021-10-23 22:00:57 +03:00
Andrey Volk fcaaf20c7d [Core] switch_ivr: Restrict the misuse of uuid_hold API. Add switch_hold unit-test. 2021-10-23 22:00:52 +03:00
Chris Rienzo a26d0c39b0 [core] Add switch_log_meta_printf() and switch_log_meta_vprintf() to allow JSON metadata to tag along with the log message. 2021-10-23 22:00:40 +03:00