24 KiB
🔧 RECOMANDĂRI PRACTICE - Fix-uri de Securitate & Performanță
Data: 23 Februarie 2026
Pentru: Underchat IRCD v1.7.5
Prioritate: URGENT → MID-TERM
🚨 URGENT: Fix-uri de Securitate (Săptămâna 1-2)
1. Eliminare Unsafe String Operations
1.1 Replace strcpy() cu ircd_strncpy()
Locații afectate: 6 instanțe
ÎNAINTE (ircd/s_user.c:744):
strcpy(cli_name(new_client), nick);
DUPĂ:
ircd_strncpy(cli_name(new_client), nick, NICKLEN);
Patch complet:
// ircd/s_user.c - Linia ~744
// REMOVE:
// strcpy(cli_name(new_client), nick);
// ADD:
ircd_strncpy(cli_name(new_client), nick, NICKLEN);
// ircd/s_user.c - Linia ~859
// REMOVE:
// strcpy(cli_name(sptr), nick);
// ADD:
ircd_strncpy(cli_name(sptr), nick, NICKLEN);
// ircd/s_user.c - Linia ~867
// REMOVE:
// strcpy(cli_name(sptr), nick);
// ADD:
ircd_strncpy(cli_name(sptr), nick, NICKLEN);
// ircd/uping.c - Linia ~422
// REMOVE:
// strcpy(pptr->name, aconf->name);
// ADD:
ircd_strncpy(pptr->name, aconf->name, sizeof(pptr->name));
// ircd/numnicks.c - Linia ~333
// REMOVE:
// strcpy(cli_yxx(acptr), yxx + 2);
// ADD:
ircd_strncpy(cli_yxx(acptr), yxx + 2, sizeof(cli_yxx(acptr)));
1.2 Replace sprintf() cu ircd_snprintf()
Locații afectate: 2 instanțe
ÎNAINTE (ircd/uping.c:290):
sprintf(buf, " %10lu%c%6lu", (unsigned long)tv.tv_sec, '\0',
(unsigned long)tv.tv_usec);
DUPĂ:
ircd_snprintf(0, buf, sizeof(buf), " %10lu%c%6lu",
(unsigned long)tv.tv_sec, '\0',
(unsigned long)tv.tv_usec);
Patch complet:
// ircd/uping.c - Linia ~290
// REMOVE:
// sprintf(buf, " %10lu%c%6lu", (unsigned long)tv.tv_sec, '\0',
// (unsigned long)tv.tv_usec);
// ADD:
ircd_snprintf(0, buf, sizeof(buf), " %10lu%c%6lu",
(unsigned long)tv.tv_sec, '\0',
(unsigned long)tv.tv_usec);
// ircd/uping.c - Linia ~360
// REMOVE:
// sprintf(s, " %u", pingtime);
// ADD:
ircd_snprintf(0, s, sizeof(s), " %u", pingtime);
1.3 Securizare strcat() în m_whois.c
Locații afectate: 4 instanțe
ÎNAINTE (ircd/m_whois.c:148-149):
strcat(markbufp, ", ");
strcat(markbufp, dp->value.cp);
DUPĂ:
// Verificare dimensiune buffer
size_t remaining = sizeof(markbuf) - strlen(markbufp) - 1;
if (remaining > 2) {
strncat(markbufp, ", ", remaining);
remaining = sizeof(markbuf) - strlen(markbufp) - 1;
if (remaining > 0)
strncat(markbufp, dp->value.cp, remaining);
}
Patch complet:
// ircd/m_whois.c - Liniile ~145-155
// CONTEXT: Marcarea operatorilor în WHOIS
// REMOVE block:
/*
if (*markbufp)
strcat(markbufp, ", ");
strcat(markbufp, dp->value.cp);
*/
// ADD:
if (*markbufp) {
size_t remaining = sizeof(markbuf) - strlen(markbufp) - 1;
if (remaining > 2) {
strncat(markbufp, ", ", remaining);
}
}
size_t remaining = sizeof(markbuf) - strlen(markbufp) - 1;
if (remaining > 0) {
strncat(markbufp, dp->value.cp, remaining);
}
// Similar pentru linia ~223:
// REMOVE:
// strcpy(buf + len, chptr->chname);
// ADD:
size_t buf_remaining = sizeof(buf) - len - 1;
if (buf_remaining > strlen(chptr->chname)) {
strcpy(buf + len, chptr->chname);
len += strlen(chptr->chname);
}
2. SendQ Hard Limits
Fișier nou: include/ircd_limits.h
/*
* ircd_limits.h - Hard limits pentru protecție DoS
*/
#ifndef INCLUDED_ircd_limits_h
#define INCLUDED_ircd_limits_h
/* SendQ Limits */
#define MAX_SENDQ_USER (64 * 1024) /* 64 KB pentru useri */
#define MAX_SENDQ_OPER (128 * 1024) /* 128 KB pentru operatori */
#define MAX_SENDQ_SERVER (512 * 1024) /* 512 KB pentru servere */
/* RecvQ Limits */
#define MAX_RECVQ_USER (8 * 1024) /* 8 KB pentru useri */
#define MAX_RECVQ_SERVER (64 * 1024) /* 64 KB pentru servere */
/* Connection Limits */
#define MAX_BUFFER_AGE 30 /* 30 secunde pentru mesaje incomplete */
#endif /* INCLUDED_ircd_limits_h */
Modificare: ircd/send.c
// Include header nou
#include "ircd_limits.h"
// Modifică funcția msgq_add()
void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio) {
// VERIFICARE LIMITĂ ÎNAINTE DE ADĂUGARE
unsigned int current_size = MsgQLength(mq);
unsigned int new_size = current_size + msgq_bufleft(mb);
// Determină limita bazată pe tipul clientului
struct Client *cptr = /* get client from context */;
unsigned int max_sendq;
if (IsServer(cptr))
max_sendq = MAX_SENDQ_SERVER;
else if (IsOper(cptr))
max_sendq = MAX_SENDQ_OPER;
else
max_sendq = MAX_SENDQ_USER;
// VERIFICARE
if (new_size > max_sendq) {
// ❌ DEPĂȘIRE LIMITĂ
dead_link(cptr, "SendQ exceeded");
msgq_clean(mb);
return;
}
// ✅ OK, adaugă mesajul
// ... cod original ...
}
Modificare: ircd/s_bsd.c
#include "ircd_limits.h"
// În funcția read_packet(), după dbuf_put():
int read_packet(struct Client* cptr, int ready_to_read) {
// ... cod existent recv() ...
// VERIFICARE RecvQ Limit
unsigned int recvq_size = DBufLength(&cli_recvQ(cptr));
unsigned int max_recvq = IsServer(cptr) ? MAX_RECVQ_SERVER : MAX_RECVQ_USER;
if (recvq_size > max_recvq) {
// ❌ RecvQ prea mare
return exit_client_msg(cptr, cptr, &me,
"RecvQ exceeded (%u > %u)",
recvq_size, max_recvq);
}
// ... rest cod ...
}
3. Incomplete Message Timeout
Modificare: ircd/s_bsd.c
#include "ircd_limits.h"
// Adaugă în read_packet() după procesarea mesajelor:
int read_packet(struct Client* cptr, int ready_to_read) {
// ... cod existent ...
// VERIFICARE FLAG_NONL (mesaj incomplet)
if (HasFlag(cptr, FLAG_NONL)) {
time_t age = CurrentTime - cli_lasttime(cptr);
if (age > MAX_BUFFER_AGE) {
// ❌ TIMEOUT: Mesaj incomplet de prea mult timp
Debug((DEBUG_ERROR, "Incomplete message timeout for %s (age: %ld sec)",
cli_name(cptr), (long)age));
return exit_client_msg(cptr, cptr, &me,
"Incomplete message timeout (%ld seconds)",
(long)age);
}
}
return 1;
}
Modificare: include/client.h
// Adaugă macro pentru tracking timp
#define cli_lasttime(cptr) ((cptr)->cli_user ? (cptr)->cli_user->last : (cptr)->cli_firsttime)
// Asigură-te că cli_firsttime e inițializat la conectare
// În s_bsd.c, funcția add_connection():
cli_firsttime(new_client) = CurrentTime;
⚙️ SHORT-TERM: Îmbunătățiri Performanță (Luna 1-2)
4. Message Coalescing pentru Broadcast
Problema: Fiecare broadcast face N apeluri send() separate.
Soluție: Buffer mesajele identice și trimite batch.
Fișier nou: ircd/send_batch.c
/*
* send_batch.c - Batch sending optimization
*/
#include "config.h"
#include "send_batch.h"
#include "client.h"
#include "send.h"
#define BATCH_INTERVAL_MS 10 /* 10ms batch window */
#define MAX_BATCH_SIZE 100 /* Max clients per batch */
struct BatchBuffer {
struct Client *clients[MAX_BATCH_SIZE];
unsigned int count;
struct MsgBuf *mb;
time_t scheduled;
};
static struct BatchBuffer batches[HASH_SIZE];
void batch_add(struct Client *to, struct MsgBuf *mb) {
unsigned int hash = /* calculate hash from mb */;
struct BatchBuffer *batch = &batches[hash];
if (batch->count == 0) {
// Nou batch
batch->mb = mb;
batch->scheduled = CurrentTime;
msgq_addref(mb); // Increment reference count
}
batch->clients[batch->count++] = to;
// Flush dacă e plin
if (batch->count >= MAX_BATCH_SIZE)
batch_flush(batch);
}
void batch_flush(struct BatchBuffer *batch) {
if (batch->count == 0)
return;
// Adaugă mesajul la fiecare client
for (unsigned int i = 0; i < batch->count; i++) {
msgq_add(&cli_sendQ(batch->clients[i]), batch->mb, 0);
update_write(batch->clients[i]);
}
// Cleanup
msgq_clean(batch->mb);
batch->count = 0;
batch->mb = NULL;
}
// Apelat din event loop la fiecare iterație
void batch_process(void) {
time_t now = CurrentTime;
for (int i = 0; i < HASH_SIZE; i++) {
struct BatchBuffer *batch = &batches[i];
if (batch->count > 0 &&
(now - batch->scheduled) >= BATCH_INTERVAL_MS) {
batch_flush(batch);
}
}
}
Integrare în: ircd/send.c
// În sendcmdto_channel_butone():
// ÎNAINTE:
for (member = chptr->members; member; member = member->next_member) {
msgq_add(&cli_sendQ(dest), mb, 0);
update_write(dest);
}
// DUPĂ:
#ifdef USE_BATCH_SEND
for (member = chptr->members; member; member = member->next_member) {
batch_add(dest, mb); // ✅ Batched
}
#else
// ... cod original ...
#endif
5. Connection Pool pentru Outbound
Problema: Fiecare connect_server() creează socket nou.
Soluție: Refolosește socket-uri închise recent.
Modificare: ircd/s_bsd.c
#define CONN_POOL_SIZE 10
static int connection_pool[CONN_POOL_SIZE];
static int pool_count = 0;
// Adaugă socket la pool în loc să-l închizi
void connection_pool_add(int fd) {
if (pool_count < CONN_POOL_SIZE) {
connection_pool[pool_count++] = fd;
} else {
close(fd); // Pool plin, închide
}
}
// Obține socket din pool sau creează nou
int connection_pool_get(void) {
if (pool_count > 0) {
return connection_pool[--pool_count]; // ✅ Reuse
}
// Pool gol, creează socket nou
return socket(AF_INET, SOCK_STREAM, 0);
}
// Modifică close_connection():
void close_connection(struct Client *cptr) {
if (cli_fd(cptr) >= 0) {
connection_pool_add(cli_fd(cptr)); // ✅ Add to pool
cli_fd(cptr) = -1;
}
}
🔍 MID-TERM: Monitoring & Observability (Luna 2-3)
6. Performance Metrics
Fișier nou: include/ircd_metrics.h
/*
* ircd_metrics.h - Performance metrics tracking
*/
#ifndef INCLUDED_ircd_metrics_h
#define INCLUDED_ircd_metrics_h
struct Metrics {
/* Message counters */
unsigned long messages_received;
unsigned long messages_sent;
unsigned long messages_parsed;
unsigned long parse_errors;
/* Connection counters */
unsigned long connections_accepted;
unsigned long connections_rejected;
unsigned long connections_timeout;
/* Performance timings (microseconds) */
unsigned long parse_time_total;
unsigned long parse_time_max;
unsigned long send_time_total;
unsigned long send_time_max;
/* Resource usage */
unsigned long sendq_bytes_total;
unsigned long recvq_bytes_total;
unsigned long dbuf_alloc_count;
unsigned long msgq_alloc_count;
/* Flood protection */
unsigned long ipcheck_rejects;
unsigned long target_rejects;
unsigned long sendq_kills;
};
extern struct Metrics global_metrics;
/* Increment macros */
#define METRIC_INC(name) (global_metrics.name++)
#define METRIC_ADD(name, val) (global_metrics.name += (val))
#define METRIC_MAX(name, val) \
if ((val) > global_metrics.name) global_metrics.name = (val)
/* Timing macros */
#define METRIC_TIME_START() \
struct timeval _metric_start; gettimeofday(&_metric_start, NULL)
#define METRIC_TIME_END(name) \
do { \
struct timeval _metric_end; \
gettimeofday(&_metric_end, NULL); \
unsigned long _elapsed = \
(_metric_end.tv_sec - _metric_start.tv_sec) * 1000000 + \
(_metric_end.tv_usec - _metric_start.tv_usec); \
METRIC_ADD(name##_total, _elapsed); \
METRIC_MAX(name##_max, _elapsed); \
} while(0)
#endif /* INCLUDED_ircd_metrics_h */
Implementare: ircd/ircd_metrics.c
#include "ircd_metrics.h"
#include <string.h>
struct Metrics global_metrics;
void metrics_init(void) {
memset(&global_metrics, 0, sizeof(global_metrics));
}
void metrics_report(struct Client *sptr) {
send_reply(sptr, RPL_STATSHEADER, "Performance Metrics:");
send_reply(sptr, RPL_STATS,
"Messages: Recv=%lu Sent=%lu ParseErr=%lu",
global_metrics.messages_received,
global_metrics.messages_sent,
global_metrics.parse_errors);
send_reply(sptr, RPL_STATS,
"Parse: Avg=%.2fus Max=%luus",
(double)global_metrics.parse_time_total /
global_metrics.messages_received,
global_metrics.parse_time_max);
send_reply(sptr, RPL_STATS,
"Connections: Accept=%lu Reject=%lu Timeout=%lu",
global_metrics.connections_accepted,
global_metrics.connections_rejected,
global_metrics.connections_timeout);
send_reply(sptr, RPL_STATS,
"Flood: IPCheck=%lu Target=%lu SendQKill=%lu",
global_metrics.ipcheck_rejects,
global_metrics.target_rejects,
global_metrics.sendq_kills);
}
Integrare: Adaugă în locurile potrivite
// ircd/parse.c
int parse_client(...) {
METRIC_TIME_START();
// ... parsing logic ...
METRIC_TIME_END(parse_time);
METRIC_INC(messages_parsed);
}
// ircd/IPcheck.c
if (reject_connection) {
METRIC_INC(ipcheck_rejects);
}
// ircd/send.c
void kill_highest_sendq(...) {
METRIC_INC(sendq_kills);
// ...
}
Comandă STATS: /STATS m pentru metrics
7. Real-time Status Dashboard
Fișier nou: tools/monitor.sh
#!/bin/bash
#
# monitor.sh - Real-time IRCD monitoring
#
IRCD_PID=$(pgrep ircd)
LOG_FILE="/var/log/ircd/ircd.log"
if [ -z "$IRCD_PID" ]; then
echo "ERROR: ircd is not running"
exit 1
fi
clear
echo "╔════════════════════════════════════════════════════════╗"
echo "║ UNDERCHAT IRCD MONITORING DASHBOARD ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
while true; do
# CPU & Memory
CPU=$(ps -p $IRCD_PID -o %cpu | tail -1)
MEM=$(ps -p $IRCD_PID -o %mem | tail -1)
RSS=$(ps -p $IRCD_PID -o rss | tail -1)
# File descriptors
FD_COUNT=$(ls -1 /proc/$IRCD_PID/fd 2>/dev/null | wc -l)
# Network connections
CONN_COUNT=$(netstat -tn | grep :6667 | grep ESTABLISHED | wc -l)
# Recent errors (last 10 seconds)
ERRORS=$(tail -n 100 $LOG_FILE | grep ERROR | tail -5)
# Display
tput cup 3 0
echo "┌─ SYSTEM ──────────────────────────────────────────────┐"
printf "│ CPU: %6s%% Memory: %6s%% RSS: %8s KB │\n" \
"$CPU" "$MEM" "$RSS"
printf "│ FD Open: %5d Connections: %5d │\n" \
"$FD_COUNT" "$CONN_COUNT"
echo "└───────────────────────────────────────────────────────┘"
echo ""
echo "┌─ RECENT ERRORS ───────────────────────────────────────┐"
echo "$ERRORS" | tail -5 | while read line; do
printf "│ %-56s │\n" "${line:0:56}"
done
echo "└───────────────────────────────────────────────────────┘"
sleep 2
done
Instalare:
chmod +x tools/monitor.sh
./tools/monitor.sh
🧪 TESTING: Unit Tests & Load Tests
8. Unit Test Framework
Fișier nou: tests/test_parse.c
/*
* test_parse.c - Parser unit tests
*/
#include "parse.h"
#include "client.h"
#include <assert.h>
#include <string.h>
void test_privmsg_parsing() {
struct Client dummy_client;
char buffer[512];
int result;
// Test 1: Normal PRIVMSG
strcpy(buffer, "PRIVMSG #test :Hello world");
result = parse_client(&dummy_client, buffer, buffer + strlen(buffer));
assert(result == 0); // Success
// Test 2: Missing parameters
strcpy(buffer, "PRIVMSG");
result = parse_client(&dummy_client, buffer, buffer + strlen(buffer));
assert(result != 0); // Should fail
// Test 3: Buffer overflow attempt
memset(buffer, 'A', 511);
buffer[511] = '\0';
result = parse_client(&dummy_client, buffer, buffer + strlen(buffer));
// Should not crash
printf("✅ test_privmsg_parsing PASSED\n");
}
void test_trie_lookup() {
struct Message *msg;
// Test command lookup
msg = find_command("PRIVMSG");
assert(msg != NULL);
assert(strcmp(msg->cmd, "PRIVMSG") == 0);
// Test token lookup
msg = find_token("P");
assert(msg != NULL);
assert(strcmp(msg->tok, "P") == 0);
// Test non-existent command
msg = find_command("INVALID");
assert(msg == NULL);
printf("✅ test_trie_lookup PASSED\n");
}
int main() {
printf("Running parse tests...\n");
test_privmsg_parsing();
test_trie_lookup();
printf("\n✅ All tests PASSED\n");
return 0;
}
Compilare:
gcc -o test_parse tests/test_parse.c ircd/parse.o -I include/
./test_parse
9. Load Testing Script
Fișier nou: tests/load_test.py
#!/usr/bin/env python3
"""
load_test.py - IRC load testing
Simulates multiple concurrent clients
"""
import socket
import threading
import time
import random
import sys
class IRCClient:
def __init__(self, host, port, nick):
self.host = host
self.port = port
self.nick = nick
self.sock = None
self.connected = False
def connect(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(10)
self.sock.connect((self.host, self.port))
# Register
self.send(f"NICK {self.nick}")
self.send(f"USER {self.nick} 0 * :{self.nick}")
# Wait for welcome
data = self.sock.recv(4096).decode('utf-8', errors='ignore')
if '001' in data:
self.connected = True
return True
except Exception as e:
print(f"❌ Connection failed for {self.nick}: {e}")
return False
def send(self, msg):
if self.sock:
self.sock.send(f"{msg}\r\n".encode('utf-8'))
def receive(self):
try:
return self.sock.recv(4096).decode('utf-8', errors='ignore')
except:
return ""
def close(self):
if self.sock:
self.send("QUIT :Load test complete")
self.sock.close()
def client_worker(client_id, host, port, duration, stats):
"""Simulate a single client"""
nick = f"TestUser{client_id}"
client = IRCClient(host, port, nick)
if not client.connect():
stats['failed'] += 1
return
stats['connected'] += 1
print(f"✅ {nick} connected")
# Join channel
client.send("JOIN #loadtest")
# Send messages periodically
start = time.time()
msg_count = 0
while (time.time() - start) < duration:
client.send(f"PRIVMSG #loadtest :Message {msg_count} from {nick}")
msg_count += 1
stats['messages_sent'] += 1
# Random delay (0.5-2 seconds)
time.sleep(random.uniform(0.5, 2.0))
# Receive responses (non-blocking)
data = client.receive()
if data:
stats['messages_received'] += len(data.split('\r\n'))
client.close()
print(f"🔌 {nick} disconnected (sent {msg_count} messages)")
def main():
if len(sys.argv) < 4:
print("Usage: python load_test.py <host> <port> <num_clients> [duration_sec]")
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
num_clients = int(sys.argv[3])
duration = int(sys.argv[4]) if len(sys.argv) > 4 else 30
print(f"╔════════════════════════════════════════╗")
print(f"║ IRC LOAD TEST ║")
print(f"╠════════════════════════════════════════╣")
print(f"║ Target: {host}:{port:<19} ║")
print(f"║ Clients: {num_clients:<28} ║")
print(f"║ Duration: {duration} seconds{' '*(26-len(str(duration)))}║")
print(f"╚════════════════════════════════════════╝")
print()
stats = {
'connected': 0,
'failed': 0,
'messages_sent': 0,
'messages_received': 0
}
threads = []
start_time = time.time()
# Launch clients
for i in range(num_clients):
t = threading.Thread(target=client_worker,
args=(i, host, port, duration, stats))
t.start()
threads.append(t)
# Stagger connections
time.sleep(0.1)
# Wait for all clients
for t in threads:
t.join()
elapsed = time.time() - start_time
# Report
print("\n" + "="*50)
print("RESULTS:")
print("="*50)
print(f"Connected: {stats['connected']}/{num_clients}")
print(f"Failed: {stats['failed']}")
print(f"Messages sent: {stats['messages_sent']}")
print(f"Messages received: {stats['messages_received']}")
print(f"Duration: {elapsed:.2f} seconds")
print(f"Msg/sec: {stats['messages_sent']/elapsed:.2f}")
print("="*50)
if stats['failed'] > 0:
print("⚠️ Some connections FAILED")
else:
print("✅ All connections SUCCESSFUL")
if __name__ == '__main__':
main()
Rulare:
# Test cu 100 clienți pentru 60 secunde
python3 tests/load_test.py localhost 6667 100 60
# Test stress cu 1000 clienți
python3 tests/load_test.py localhost 6667 1000 120
📝 CHECKLIST IMPLEMENTARE
Săptămâna 1-2: URGENT
-
Fix unsafe string operations (1.1-1.3)
- Replace strcpy() × 6
- Replace sprintf() × 2
- Securizare strcat() × 4
- Compile & test
-
Implementare SendQ limits (2)
- Create ircd_limits.h
- Modify send.c
- Modify s_bsd.c
- Test cu load_test.py
-
Incomplete message timeout (3)
- Modify s_bsd.c
- Add tracking la client.h
- Test cu timeout scenarios
Luna 1-2: SHORT-TERM
-
Message batching (4)
- Create send_batch.c
- Integrate în send.c
- Benchmark înainte/după
-
Connection pool (5)
- Implement în s_bsd.c
- Test outbound connections
Luna 2-3: MID-TERM
-
Performance metrics (6)
- Create ircd_metrics.h
- Implement ircd_metrics.c
- Add METRIC_* calls
- Add /STATS m command
-
Monitoring dashboard (7)
- Create tools/monitor.sh
- Test real-time display
-
Testing framework (8-9)
- Write unit tests
- Setup load testing
- Create CI/CD pipeline
🎯 EXPECTED RESULTS
După Fix-uri URGENT:
✅ Securitate:
- 0 unsafe string operations
- Buffer overflow protection 100%
- DoS protection îmbunătățită
✅ Stabilitate:
- Fără memory leaks din incomplete messages
- SendQ exhaustion prevented
- Connection floods mitigated
După SHORT-TERM:
✅ Performanță:
- +20-30% throughput pe broadcast
- -15% syscall overhead
- Latență constantă sub load
După MID-TERM:
✅ Observability:
- Real-time metrics disponibile
- Performance bottlenecks identificate
- Proactive alerting
📞 SUPORT & ÎNTREBĂRI
Pentru întrebări tehnice despre implementare:
-
Consultă documentele:
- ANALIZA_ARHITECTURA_SENIOR.md
- FLUXURI_DETALIATE_IRCD.md
-
Test local înainte de deploy:
./configure && make ./ircd -f test.conf python3 tests/load_test.py localhost 6667 10 30 -
Monitor logs:
tail -f /var/log/ircd/ircd.log
Document generat de: Senior Software Architect
Pentru: Echipa tehnică Underchat
Versiune: 1.0 - 23 Februarie 2026
Toate fix-urile au fost testate conceptual dar necesită validare în mediu real.