درگاههای شبکه خصوصی مجازی متصل به ستون فقرات اینترنت عمومی همواره با یک عدم تقارن محاسباتی بنیادین روبهرو هستند. هنگامی که یک کلاینت قصد برقراری ارتباط در یک تونل امن را دارد، پروتکلهای رمزنگاری ملزم به انجام محاسبات ریاضی نامتقارن سنگین—مانند ضرب اسکالر روی منحنیهای بیضوی Curve25519—جهت توافق بر سر کلیدهای احرازشده نشست میباشند.
در حالی که انجام یک ضرب اسکالر Curve25519 روی پردازندههای سرور نوین کسری از میلیثانیه زمان میبرد، ارسال یک بسته داده ساختگی UDP با حجم ۱۴۸ بایت روی پیوند شبکه ۱۰ گیگابیتی تنها نیازمند چند نانوثانیه است. یک مهاجم با ارسال انبوه بستههای آغازین جعلی و جعل نشانیهای IP مبدا میتواند به سرعت تمامی هستههای پردازنده درگاه را اشباع کرده و مانع از تکمیل دستتکانی کاربران مجاز گردد.
برای مقابله قاطع با تهدید حملات محرومسازی از سرویس (DoS) و سرریز حافظه، وایرگارد یک الگوریتم اختصاصی سطل ژتون (Token Bucket) را مستقیماً در مسیر دادههای شبکه هسته لینوکس پیادهسازی کرده است (drivers/net/wireguard/ratelimiter.c). وایرگارد با کنترل نرخ جریان بستههای احرازنشده بر پایه نشانی IP پیش از فراخوانی توابع رمزنگاری سنگین، ظرفیت پردازش دادهها با نرخ خط فیزیکی را حتی در زیر شدیدترین حملات پایدار نگه میدارد.
+-----------------------------------------------------------------------------+
| خط لوله محدودسازی نرخ دستتکانی در هسته وایرگارد |
| |
| بسته ورودی UDP (نوع ۱: آغاز دستتکانی) |
| [ تایید اعتبار شناسه MAC1 از طریق BLAKE2s ] |
| | |
| v |
| wg_ratelimiter_allow_ip(net, ip_addr) |
| | |
| v |
| ورود به بخش خواندن بدون قفل rcu_read_lock() |
| محاسبه باکت با SipHash: siphash(&ip, secret_key) |
| | |
| v |
| پیمایش زنجیره hlist در table_v4 یا table_v6 |
| | |
| +-----------+-----------+ |
| | | |
| v v |
| [ ورودی IP یافت شد ] [ ورودی موجود نیست ] |
| | | |
| | v |
| | تخصیص ساختار جدید ratelimiter_entry |
| | درج در باکت جدول (قفل اتمیک) |
| | | |
| +----------->+<---------+ |
| | |
| v |
| بازیابی ژتونها بر مبنای نانوثانیههای سپریشده |
| (ظرفیت: ۲۰ ژتون، نرخ پر شدن: ۱ ژتون در هر ۱۰۰ میلیثانیه) |
| | |
| +------------+------------+ |
| | | |
| v v |
| [ ژتون موجود >= ۱ ] [ سطل خالی است (ژتون < ۱) ] |
| | | |
| v v |
| کسر ۱ ژتون رد پردازش مستقیم محاسبات رمزنگاری |
| خروج از rcu_read_unlock الزام به حل چالش کوکی MAC2 (cookie.c) |
| انجام ضرب اسکالر حذف بیصدا بسته در صورت فقدان یا بطلان کوکی |
| روی منحنی Curve25519 | |
| v |
| rcu_read_unlock() |
+-----------------------------------------------------------------------------+
آسیبپذیری عدم تقارن دستتکانی در پروتکلهای سنتی
پروتکلهای متداول تونلسازی ارتباطات را با تبادلات چندمرحلهای پیچیده آغاز میکنند که بار ذخیرهسازی وضعیت زیادی را بر سرور تحمیل مینماید. در پروتکل استاندارد IPsec IKEv2، سرور با دریافت نخستین پیام IKE_SA_INIT ساختارهای نیمهباز را در حافظه تخصیص داده و پیش از احراز هویت اقدام به نگهداری دادهها میکند. هجوم ناگهانی بستهها حافظه هسته را پر کرده و منجر به خطای کمبود حافظه در سامانه میشود.
در سوی دیگر، نرمافزارهای مبتنی بر OpenVPN از ساختارهای فضای کاربری OpenSSL یا mbedTLS استفاده میکنند. با رسیدن هر پیام ورودی، جابهجاییهای مکرر بین هسته و فضای کاربر، بررسیهای زنجیره گواهی و اعتبارسنجی کلیدهای RSA یا ECDSA صورت میپذیرد. در ترافیکهای انبوه، این فرآیندها تمام توان پردازنده را مصرف کرده و سبب قطعی اتصالهای کاربران فعال میشوند.
علاوه بر این، بهکارگیری قوانین ساده دیواره آتش یا ماژولهای معمولی با چالشهای فنی همراه است:
۱. ازدیاد ورودیهای جدول وضعیت: ردیابی صدها هزار نشانی جعلی متعلق به باتنتها جدول اتصالات فایروال را اشباع میکند. ۲. رقابت شدید بر سر قفلها: استفاده از قفلهای سراسری در پردازندههای چندهستهای سبب اتلاف شدید منابع برای همگامسازی حافظه کش میگردد. ۳. حملات پیچیدگی الگوریتمی (Hash-DoS): توابع هش فاقد کلید به مهاجم اجازه میدهند نشانیهایی تولید کند که به یک باکت مشترک برخورد کرده و سرعت جستجو را از $O(1)$ به $O(N)$ تنزل دهند.
کالبدشکافی ratelimiter.c: سازوکار سطل ژتون در هسته لینوکس
طراحان وایرگارد با پیادهسازی مستقیم در drivers/net/wireguard/ratelimiter.c این موانع را برطرف ساختهاند. درایور دو جدول هش مجزا میسازد: table_v4 برای نشانیهای IPv4 و table_v6 برای IPv6.
struct ratelimiter_entry {
u64 last_time_ns;
u32 tokens;
spinlock_t lock;
struct hlist_node hash;
struct rcu_head rcu;
union {
__be32 ip;
struct in6_addr ip6;
};
};
هر ورودی نمایانگر یک سطل ژتون مجزا برای نشانی کلاینت راه دور است:
- گنجایش انفجاری (
PACKETS_BURST): برابر با ۲۰ ژتون تنظیم شده تا کلاینتهای مجاز در زمان جابهجایی میان شبکهها بدون تاخیر اتصال را برقرار کنند. - نرخ پر شدن مجدد (
PACKETS_PER_SECOND): تزریق ۱۰ ژتون در هر ثانیه (۱ ژتون در هر ۱۰۰ میلیثانیه) که بر مبنای ساعت نانوثانیهای هسته (ktime_get_coarse_boottime_ns()) به شکل پویا محاسبه میشود. - بار حافظه حداقلی: ساختار جمعوجور تضمین میکند دهها هزار ورودی همزمان تنها حجم اندکی از رم هسته را مصرف کنند.
۱. ایمنسازی جداول هش در برابر تصادم با SipHash
برای مصون ماندن جدول از حملات پیچیدگی الگوریتمی، شماره باکتها به وسیله تابع شبهتصادفی SipHash محاسبه میشود. در زمان بارگذاری، وایرگارد یک کلید تصادفی ۱۲۸ بیتی کاملاً محرمانه از مخزن سیستم دریافت میکند:
static inline u32 entry_hash(const struct ratelimiter_entry *entry)
{
return siphash_1u32((__force u32)entry->ip, &table_key);
}
پنهان بودن کلید table_key در هسته مانع از آن میشود که مهاجم بتواند نشانیهای دارای تصادم را محاسبه کند. توزیع دادهها بر اساس توزیع پواسون صورت گرفته و زمان دستیابی به باکتها همواره در مرتبه زمانی ثابت $O(1)$ باقی میماند.
۲. خواندن داده بدون قفل با RCU و قفلهای محلی
برای پردازش دادهها در سرعت بالا، پیمایش جداول در بخشهای خواندن Read-Copy Update (RCU) انجام میشود:
bool wg_ratelimiter_allow_ip(struct ratelimiter *limiter, struct sk_buff *skb)
{
struct ratelimiter_entry *entry;
u32 hash;
rcu_read_lock();
hash = entry_hash_from_skb(skb);
hlist_for_each_entry_rcu(entry, &limiter->table_v4[hash & limiter->mask], hash) {
if (entry->ip == ip) {
bool allowed = deduct_token(entry);
rcu_read_unlock();
return allowed;
}
}
rcu_read_unlock();
return allocate_and_insert_entry(limiter, ip);
}
در مسیر سریع، هستههای پردازنده بدون نیاز به قفلهای سراسری نشانی هدف را پیدا میکنند. رشته پردازشی تنها قفل محلی همان ورودی (entry->lock) را جهت کسر ژتون در اختیار میگیرد. هستههای دیگر که در حال بررسی ترافیک سایر نشانیها هستند به صورت موازی به کار خود ادامه میدهند.
۳. جابهجایی دفاعی به آزمون کوکیهای بدون حالت MAC2
در صورتی که نرخ تبادل یک نشانی از ظرفیت مجاز سطل فراتر رود، وایرگارد بسته را مستقیماً دور نمیریزد بلکه وضعیت دفاعی تطبیقی را فعال میکند:
حالت عادی (ژتون موجود است):
بسته کلاینت [ نوع ۱ | احرازنشده | MAC1 ]
--> سطل ژتون تایید میکند
--> محاسبه کلیدهای Curve25519
--> ارسال پاسخ نوع ۲
حالت اضافه بار (سطل خالی است):
بسته کلاینت [ نوع ۱ | ترافیک مازاد بر سقف | MAC1 ]
--> خودداری از محاسبات سنگین ریاضی
--> در صورت نبود MAC2: صدور بسته نوع ۳ حاوی کوکی بدون حالت
--> کلاینت کوکی MAC2 را ساخته و بسته نوع ۱ [ MAC1 + MAC2 ] را بازمیفرستد
--> سرور کوکی را به سرعت بررسی کرده و ارتباط را تایید مینماید
در جریان حملات، درگاه از پردازش سنگین Curve25519 برای بستههای تاییدنشده امتناع میورزد و از کلاینت میخواهد کوکی متصل به نشانی و پورت را بازگرداند. از آنجا که ساخت و سنجش کوکی تنها به یک عملیات هش متقارن BLAKE2s نیاز دارد، سرور میتواند میلیونها بسته را در ثانیه مدیریت کند. کلاینت واقعی چالش را حل کرده و متصل میماند، در حالی که ترافیک مخرب بلافاصله خنثی میشود.
بازیافت خودکار حافظه با صفهای تعویق کار
در جریان حملات توزیعشده با میلیونها نشانی تصادفی، جدول ثبت نشستها بدون بازیافت دورهای با رشد فزاینده روبهرو خواهد شد.
برای محافظت از پایداری حافظه سرور، وایرگارد از صفهای به تعویق افتاده لینوکس (schedule_delayed_work) برای پاکسازی پسزمینه بهره میگیرد:
static void cleanup_entries(struct work_struct *work)
{
struct ratelimiter_entry *entry;
struct hlist_node *n;
u64 now = ktime_get_coarse_boottime_ns();
spin_lock_bh(&table_lock);
for (int i = 0; i < HASH_SIZE; ++i) {
hlist_for_each_entry_safe(entry, n, &table[i], hash) {
if (now - entry->last_time_ns > EXPIRATION_INTERVAL_NS) {
hlist_del_rcu(&entry->hash);
kfree_rcu(entry, rcu);
}
}
}
spin_unlock_bh(&table_lock);
}
این سازوکار پاکسازی اقدامات زیر را مدیریت مینماید:
- حذف ورودیهای غیرفعال: هر دادهای که در بازه انقضا ترافیکی نداشته باشد با تابع
hlist_del_rcu()از جدول جدا میشود. - آزادسازی ایمن با RCU: حافظه تنها پس از عبور تمام هستهها از دوره استراحت توسط
kfree_rcu()آزاد میشود تا هیچگونه خطای دسترسی همزمان رخ ندهد. - مهار ظرفیت حافظه: در صورت رسیدن تعداد ورودیها به سقف مجاز تحت حملات سنگین، ماژول به صورت خودکار قدیمیترین دادهها را پاک میکند تا کارکرد سیستم مختل نشود.
ابزارهای بررسی و تنظیمات هسته در لینوکس
مدیران سامانههای لینوکس میتوانند وضعیت سوکتها و صفهای شبکه وایرگارد را با دستورات استاندارد پایش نمایند.
مشاهده وضعیت بافرهای دریافت UDP روی درگاه وایرگارد:
# پایش صفهای دریافت و حافظه سوکت UDP
ss -u -a -m -p | grep 51820
بررسی توزیع بار وقفههای نرمافزاری شبکه میان هستهها:
# تحلیل توازن بار پردازش ترافیک روی پردازنده
mpstat -P ALL 1 5
تنظیم متغیرهای شبکه هسته برای افزایش تابآوری در برابر ترافیک انبوه:
# بهینهسازی صف دستگاهها و بافرهای دریافت و ارسال
sysctl -w net.core.netdev_max_backlog=100000
sysctl -w net.core.rmem_max=67108864
sysctl -w net.core.wmem_max=67108864
sysctl -w net.ipv4.udp_rmem_min=16384
تابآوری خط فیزیکی در زیرساخت یکپارچه VPNRice
تضمین تداوم پایداری شبکه در مقیاسهای تجاری مستلزم دفاع فعال در برابر امواج سیلآسای ترافیک است. شبکه جهانی Anycast در VPNRice از این معماری به صورت فراگیر بهره میگیرد:
۱. فیلترینگ سریع در لایه هسته: گرههای لبهای VPNRice با استقرار منطق سطل ژتون در مسیر دادهها، درخواستهای مخرب را پیش از رسیدن به مراحل رمزنگاری سنگین متوقف ساخته و توان پردازشی را برای انتقال دادههای کاربران حفظ مینمایند.
۲. آزمون خودکار کوکی MAC2: به هنگام جهش ترافیک مشکوک، درگاهها بلافاصله به مکانیسم تایید کوکی جابهجا میشوند تا بدون ایجاد اختلال برای کاربران حقیقی، بستههای نامعتبر را با سرعت سختافزاری حذف کنند.
۳. جداسازی کامل کلیدهای SipHash: هر دامنه مسیریابی در گرههای VPNRice کلیدهای نمکگذاری منحصربهفرد تولید میکند تا احتمال تداخل و حملات تصادم میان کلاینتها ریشهکن گردد.
همگرایی الگوریتم سطل ژتون، توابع SipHash و مدیریت حافظه RCU در هسته، شبکهای پایدار، ایمن و پرسرعت را در مقابل سنگینترین بارهای پردازشی پدید میآورد.



