Release v2.26.0 #284

Merged
TapTap merged 210 commits from dev into main 2026-09-18 19:05:52 +02:00
5 changed files with 51 additions and 19 deletions
Showing only changes of commit 3cf2e2c91f - Show all commits
+29
View File
@@ -4,6 +4,35 @@ All notable changes to FastSync are documented here. Versions match
`PROTOCOL_VERSION` (printed by `fastsync --version`); the client and server must
run the same version because the handshake is strict.
## [2.20.0] - 2026-09-13
### Security
- Cap cumulative `DirTimeList` growth and bound pre-auth config-string memory
(remote memory-exhaustion DoS).
- Daemon host access control (`hosts allow`/`hosts deny`, IPv4/IPv6/CIDR),
configurable global `max connections`, connection audit logging, and a
bounded `auth failure delay` throttle. IPv4-mapped peers are normalized and
invalid patterns are rejected at parse time (no silent fail-open).
- Honor `--timeout` for protocol I/O and bound idle/session time to defeat
keepalive slowloris; child-safe signal handling in the forked daemon.
- Compiler/linker hardening (`_FORTIFY_SOURCE`, stack protector, PIE, RELRO)
and pinned build dependencies.
### Fixed
- Use-after-free in the basis-dir oversize preflight.
- Placeholder `Data` leaks, `missing_args` leak, scanner chunk leak.
- Thread-safe logging; single fd owner and cleanup epilogue in the server
handler.
### Performance
- Metadata now crosses the wire as one packed frame (protocol 2.20.0).
- Delete keep-set and `--files-from` lookups indexed (O(n*m) → O(n)).
- Reused per-thread zstd contexts; `TCP_NODELAY` by default.
- Byte-bounded sender queues; removed a redundant scanner `stat()`.
## [2.19.0] - 2026-09-12
### Security
+1 -1
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(FastFileTransfer VERSION 2.19.0)
project(FastFileTransfer VERSION 2.20.0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 11)
+6 -4
View File
@@ -850,10 +850,12 @@ now sends the metadata as ONE packed frame: a single `int32` present flag
`FILE_METADATA_WIRE_SIZE`-byte (68-byte) field record already emitted by the
shared `metadata_to_buf()`/`metadata_from_buf()` chunk codec. Absent metadata is
a lone `int32` zero. The encoded field layout is unchanged (only the framing
collapses), so chunk-serialized blobs remain byte-identical; `PROTOCOL_VERSION`
was bumped `2.19.0 → 2.20.0` because a 2.19 peer would desynchronize on the
removed frames. The strict same-version handshake rejects any mismatch before a
byte of the frame is parsed.
collapses), so chunk-serialized blobs remain byte-identical. Protocol data is an
unframed byte stream, so the packed encoding is byte-for-byte identical to the
old field-by-field writes; `PROTOCOL_VERSION` was bumped `2.19.0 → 2.20.0` as a
deliberate lockstep-release marker rather than because of a
desynchronization. The strict same-version handshake rejects any mismatch before
a byte of the frame is parsed.
### Recommended Delivery Order
+12 -13
View File
@@ -646,19 +646,18 @@ typedef struct Config {
*
* Packed Metadata Wave: 2.19.0 -> 2.20.0.
*
* WHY the bump, grounded in the wire: metadata_send()/metadata_receive() no
* longer emit/consume the metadata as up to 12 separate per-field framed
* writes. A file's metadata now crosses the wire as ONE packed frame: a
* single int32 present flag (0 = absent, 1 = present) followed, when present,
* by the fixed FILE_METADATA_WIRE_SIZE-byte (68-byte) field record produced by
* metadata_to_buf(). A 2.19 peer would desynchronize on the removed frames
* (it would read the packed record's bytes as a stream of separate field
* frames), so the strict same-version handshake (config_receive rejects a
* mismatched version before parsing anything else) is what keeps a 2.20 client
* and a 2.19 server from ever reaching that state. The encoded field layout
* itself is unchanged (only its framing collapses), so the chunk codec, which
* already used the packed metadata_to_buf()/metadata_from_buf() codec, is
* byte-identical to before. */
* WHY the bump: metadata_send()/metadata_receive() no longer emit/consume the
* metadata as up to 12 separate per-field writes. A file's metadata now
* crosses the wire as ONE packed frame: a single int32 present flag (0 =
* absent, 1 = present) followed, when present, by the fixed
* FILE_METADATA_WIRE_SIZE-byte (68-byte) field record produced by
* metadata_to_buf(). Protocol data is an unframed byte stream, so the packed
* encoding is byte-for-byte identical to the old field-by-field writes (same
* fields, same order, same widths); the change only removes per-field syscalls.
* The bump is therefore a deliberate lockstep-release marker, not a
* desynchronization fix — the strict same-version handshake still rejects a
* mixed 2.19/2.20 deployment. The chunk codec, which already used the packed
* metadata_to_buf()/metadata_from_buf() form, is unchanged. */
#define PROTOCOL_VERSION "2.20.0"
#define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024)
/* Upper bound on total basis-dir entries (rsync caps --link-dest at 20). */
+3 -1
View File
@@ -175,7 +175,9 @@ bool str_hash_set_insert_ref(StrHashSet* set, const char* key) {
return false;
if (!str_hash_set_grow(set))
return false;
return str_hash_set_put(set, key, strlen(key)) >= 0;
/* put() returns 1 for a new slot and 0 for a duplicate; both are success. */
(void)str_hash_set_put(set, key, strlen(key));
return true;
}
static const StrHashSetSlot* str_hash_set_find_n(const StrHashSet* set, const char* key,