Skip to content

Commit a2d4964

Browse files
committed
feat: Add security features, test infrastructure, and modular binlog processing
This commit introduces critical security enhancements, comprehensive test reorganization, and modular binlog event processing architecture. Major changes: - Security: Add rate limiting (token bucket algorithm), connection limits, and network ACL with fail-closed defaults - Architecture: Refactor binlog processing into modular parser/processor/evaluator components - Testing: Reorganize test suite with focused, granular test files for better maintainability - CI/CD: Add develop branch CI workflow with build and format checking - Documentation: Update configuration docs with detailed security guidance (EN/JA) Security enhancements: - Rate limiting per client IP with configurable burst/refill (disabled by default) - TCP max_connections limit to prevent file descriptor exhaustion - Network ACL now denies all by default (fail-closed) - requires explicit allow_cidrs - Security-focused test coverage for ACL, dump operations, and connection limits Binlog refactoring: - Split binlog_reader into event_parser, event_processor, and filter_evaluator - Improve separation of concerns and testability - Enhanced GTID tracking and cancellation handling Test infrastructure improvements: - Split monolithic test files into focused units (basic, advanced, search, batch, etc.) - Add integration tests for end-to-end workflows and stress testing - Comprehensive coverage for HTTP/TCP servers, MySQL binlog, and cache operations - New tests: deadlock detection, rate limiting, security boundaries Configuration changes: - Add api.tcp.max_connections (default: 10000) - Add api.rate_limiting.{enable,capacity,refill_rate,max_clients} - Change network.allow_cidrs default behavior to deny-by-default for security - Update example configs with security-focused defaults (127.0.0.1/32)
1 parent fdb9f83 commit a2d4964

File tree

74 files changed

+12163
-2914
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+12163
-2914
lines changed

.github/workflows/develop-ci.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Develop CI
2+
3+
on:
4+
push:
5+
branches: [ develop ]
6+
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.ref }}
9+
cancel-in-progress: true
10+
11+
jobs:
12+
linux-build:
13+
name: Linux Build and Test
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Cache CMake dependencies
21+
uses: actions/cache@v4
22+
with:
23+
path: build/_deps
24+
key: ${{ runner.os }}-cmake-deps-${{ hashFiles('CMakeLists.txt', 'third_party/**') }}
25+
restore-keys: |
26+
${{ runner.os }}-cmake-deps-
27+
28+
- name: Cache ccache
29+
uses: actions/cache@v4
30+
with:
31+
path: ~/.cache/ccache
32+
key: ${{ runner.os }}-ccache-${{ github.sha }}
33+
restore-keys: |
34+
${{ runner.os }}-ccache-
35+
36+
- name: Cache LLVM installation
37+
id: cache-llvm
38+
uses: actions/cache@v4
39+
with:
40+
path: |
41+
/usr/lib/llvm-18
42+
/usr/bin/clang-format-18
43+
/usr/bin/clang-tidy-18
44+
key: ${{ runner.os }}-llvm-18
45+
46+
- name: Install dependencies
47+
run: |
48+
sudo apt-get update
49+
sudo apt-get install -y \
50+
cmake \
51+
build-essential \
52+
libmysqlclient-dev \
53+
libicu-dev \
54+
libreadline-dev \
55+
pkg-config \
56+
ccache
57+
58+
- name: Install LLVM/Clang 18
59+
if: steps.cache-llvm.outputs.cache-hit != 'true'
60+
run: |
61+
wget https://apt.llvm.org/llvm.sh
62+
chmod +x llvm.sh
63+
sudo ./llvm.sh 18
64+
sudo apt-get install -y clang-format-18 clang-tidy-18
65+
66+
- name: Setup LLVM alternatives
67+
run: |
68+
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 100
69+
sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 100
70+
71+
- name: Check code formatting
72+
run: make format-check
73+
74+
- name: Setup ccache
75+
run: |
76+
ccache --set-config=max_size=500M
77+
ccache --zero-stats
78+
79+
- name: Configure CMake
80+
env:
81+
CC: ccache gcc
82+
CXX: ccache g++
83+
run: |
84+
mkdir -p build
85+
cd build
86+
cmake -DCMAKE_BUILD_TYPE=Release \
87+
-DBUILD_TESTS=ON \
88+
-DUSE_ICU=ON \
89+
-DUSE_MYSQL=ON \
90+
..
91+
92+
- name: Build
93+
run: |
94+
cd build
95+
make -j$(nproc)
96+
97+
- name: Show ccache statistics
98+
run: ccache --show-stats
99+
100+
- name: Upload build artifacts
101+
if: failure()
102+
uses: actions/upload-artifact@v4
103+
with:
104+
name: build-logs-linux
105+
path: |
106+
build/CMakeFiles/*.log
107+
build/Testing/Temporary/

docs/en/configuration.md

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,15 @@ api:
9595
cors_allow_origin: ""
9696
default_limit: 100
9797
max_query_length: 128
98+
rate_limiting:
99+
enable: false
100+
capacity: 100
101+
refill_rate: 10
102+
max_clients: 10000
98103

99104
network:
100-
allow_cidrs: []
105+
allow_cidrs:
106+
- "127.0.0.1/32"
101107

102108
logging:
103109
level: "info"
@@ -479,8 +485,21 @@ api:
479485
tcp:
480486
bind: "127.0.0.1" # Default: loopback only. Change to 0.0.0.0 to allow remote clients.
481487
port: 11016 # Default: 11016
488+
max_connections: 10000 # Maximum concurrent connections (default: 10000)
482489
```
483490

491+
- **bind**: IP address to bind the TCP server (default: `127.0.0.1`)
492+
- Use `127.0.0.1` for localhost-only access (most secure)
493+
- Use `0.0.0.0` to accept connections from any network interface
494+
- **port**: TCP port number (default: `11016`)
495+
- **max_connections**: Maximum number of concurrent TCP connections (default: `10000`)
496+
- **SECURITY**: Prevents file descriptor exhaustion and resource starvation attacks
497+
- Connections exceeding this limit are immediately rejected and closed
498+
- Set based on system `ulimit -n` (open file limit) and available memory
499+
- **Production recommendation**: Set to half of your system's file descriptor limit
500+
- Example: If `ulimit -n` returns 65536, set `max_connections: 30000`
501+
- Each connection consumes one file descriptor plus memory for buffers
502+
484503
### HTTP API (Optional)
485504

486505
```yaml
@@ -502,35 +521,96 @@ api:
502521
- **max_query_length**: Rejects overly long boolean expressions to avoid resource exhaustion.
503522
- Default 128 characters; set to `0` to disable the guard.
504523
- The length includes search text, AND/NOT terms, and FILTER values.
524+
525+
### Rate Limiting (Optional)
526+
527+
Rate limiting protects against DoS attacks and resource exhaustion using the **token bucket algorithm**:
528+
529+
```yaml
530+
api:
531+
rate_limiting:
532+
enable: false # Default: false (disabled)
533+
capacity: 100 # Maximum tokens per client (burst size)
534+
refill_rate: 10 # Tokens added per second per client
535+
max_clients: 10000 # Maximum number of tracked clients
536+
```
537+
538+
- **enable**: Enable/disable rate limiting (default: `false`)
539+
- When disabled, no rate limiting is applied
540+
- When enabled, limits requests per client IP address
541+
- **capacity**: Maximum tokens per client (burst size, default: `100`)
542+
- Allows a burst of up to N requests before throttling kicks in
543+
- Example: With capacity=100, a client can make 100 immediate requests
544+
- **refill_rate**: Tokens added per second per client (default: `10`)
545+
- Sustained rate limit in requests/second
546+
- Example: With refill_rate=10, a client can make 10 requests/second continuously
547+
- **max_clients**: Maximum number of tracked clients (default: `10000`)
548+
- Memory management to prevent tracking too many IP addresses
549+
- Oldest inactive clients are automatically cleaned up
550+
551+
**Token Bucket Algorithm:**
552+
553+
1. Each client starts with a full bucket of tokens (capacity)
554+
2. Each request consumes 1 token
555+
3. Tokens are automatically refilled at the configured rate
556+
4. If no tokens available, request is rejected with rate limit error
557+
558+
**Example Use Cases:**
559+
560+
- **High throughput**: `capacity: 1000, refill_rate: 100` - Allows 1000 request burst, 100 req/s sustained
561+
- **Moderate protection**: `capacity: 100, refill_rate: 10` - Allows 100 request burst, 10 req/s sustained
562+
- **Strict limiting**: `capacity: 10, refill_rate: 1` - Allows 10 request burst, 1 req/s sustained
563+
564+
**Note:** Rate limiting is disabled by default. Enable it explicitly in production environments to protect against abuse.
505565
```
506566

507-
## Network Section (Optional)
567+
## Network Section (REQUIRED for Production)
508568

509-
Network security configuration:
569+
Network security configuration using IP allowlist (fail-closed by default):
510570

511-
- **allow_cidrs**: Allow CIDR list (default: `[]` = allow all)
571+
- **allow_cidrs**: Allow CIDR list (**SECURITY: Default deny when empty**)
512572
- Applies to both TCP and HTTP interfaces
513-
- When empty, all IP addresses are allowed
514-
- When specified, only connections from these IP ranges are accepted
573+
- **When empty: ALL connections are DENIED by default** (fail-closed security posture)
574+
- When specified: only connections from these IP ranges are accepted
515575
- Supports standard CIDR notation (e.g., `192.168.1.0/24`, `10.0.0.0/8`)
516576
- Multiple CIDR ranges can be specified
517577

578+
**IMPORTANT SECURITY CHANGE:** Previous versions allowed all connections when `allow_cidrs` was empty. Current version **denies all connections by default** for security. You MUST explicitly configure allowed IP ranges.
579+
580+
### Recommended Configurations
581+
582+
**Localhost only (most secure):**
583+
```yaml
584+
network:
585+
allow_cidrs:
586+
- "127.0.0.1/32" # Only local connections
587+
```
588+
589+
**Private network:**
590+
```yaml
591+
network:
592+
allow_cidrs:
593+
- "127.0.0.1/32" # Localhost
594+
- "192.168.1.0/24" # Local subnet
595+
- "10.0.0.0/8" # Private network
596+
```
597+
598+
**Allow all (NOT RECOMMENDED for production):**
518599
```yaml
519600
network:
520601
allow_cidrs:
521-
- "192.168.1.0/24"
522-
- "10.0.0.0/8"
523-
- "172.16.0.0/16"
602+
- "0.0.0.0/0" # WARNING: Allows connections from anywhere
524603
```
525604
526605
**Common CIDR ranges:**
527606
528-
- Private networks:
529-
- `10.0.0.0/8` - Class A private network
530-
- `172.16.0.0/12` - Class B private network
531-
- `192.168.0.0/16` - Class C private network
532-
- Localhost: `127.0.0.1/32`
533-
- Single IP: `192.168.1.100/32`
607+
- **Localhost:** `127.0.0.1/32` (single IP, most secure for local-only access)
608+
- **Private networks:**
609+
- `10.0.0.0/8` - Class A private network (10.0.0.0 - 10.255.255.255)
610+
- `172.16.0.0/12` - Class B private network (172.16.0.0 - 172.31.255.255)
611+
- `192.168.0.0/16` - Class C private network (192.168.0.0 - 192.168.255.255)
612+
- **Single IP:** `192.168.1.100/32` (only this specific IP)
613+
- **Allow all:** `0.0.0.0/0` (**NOT RECOMMENDED** - allows any IP address)
534614

535615
## Logging Section
536616

0 commit comments

Comments
 (0)