
nftables नियमों के परीक्षण के लिए एक नियतात्मक नेटवर्क सैंडबॉक्स। यह फ़ायरवॉल लॉजिक को सुरक्षित रूप से सत्यापित करने के लिए अल्पकालिक Linux नेटवर्क नेमस्पेस (netns) और Scapy का उपयोग करता है।
NSE क्यों? • Oracle अनुबंध • वायर पर अभिकथन • विशेषताएँ • आवश्यकताएँ • स्थापना • त्वरित शुरुआत • यह कैसे काम करता है • परियोजना संरचना
किसी लाइव Linux सिस्टम पर फ़ायरवॉल नियमसेट का परीक्षण करना महत्वपूर्ण जोखिम पैदा करता है: विकृत नियम SSH प्रबंधन सत्रों को गिरा सकते हैं, परीक्षण के दौरान स्पष्ट टेक्स्ट ट्रैफ़िक लीक कर सकते हैं, या होस्ट पर अनाथ फ़ायरवॉल तालिकाओं को सक्रिय छोड़ सकते हैं।
Network Sandbox Engine (NSE) एक सुरक्षित, पुनरुत्पादनीय परीक्षण हार्नेस प्रदान करता है। यह अल्पकालिक Linux नेटवर्क नेमस्पेस का निर्माण करता है, वर्चुअल ईथरनेट जोड़े जोड़ता है, nftables नियमसेट संकलित करता है, और Scapy का उपयोग करके कृत्रिम लेयर 2 और लेयर 3 पैकेट इंजेक्ट करता है। सभी मूल्यांकन सैंडबॉक्स नेमस्पेस के भीतर होता है: होस्ट फ़ायरवॉल स्थिति को कभी नहीं बदला जाता।
प्रमुख वास्तुशिल्प गुण:
nse_<uuid>) में लोड किए जाते हैं और टियरडाउन के दौरान पूरी तरह से हटा दिए जाते हैं।nse/ लगभग 1200 स्टेटमेंट्स है जिसमें 98% परीक्षण कवरेज है।NSE नेटवर्क नेमस्पेस बनाता है, nftables नियमसेट लोड करता है और कर्नेल ट्रेस इवेंट पढ़ता है, इसलिए यह रूट के रूप में चलता है। यह किसी भी प्रकार का सॉकेट, पोर्ट या RPC एंडपॉइंट नहीं खोलता — यह एक लाइब्रेरी और एक CLI है जिसे आप आमंत्रित करते हैं, और यह विशेषाधिकार केवल एक रन की अवधि के लिए रखता है।
संस्करण 2.1.0 ने FastAPI/Svelte वेब इंटरफ़ेस को हटा दिया जो पिछले रिलीज़
में शामिल था। वह इंटरफ़ेस 2.0.0 से आगे रूट के रूप में इन-प्रोसेस चलता था, जो एक
परीक्षण उपकरण के लिए एक बड़ी हमला सतह थी; यदि आपको इसकी आवश्यकता हो तो कोड git इतिहास में
टैग v2.0.0 पर बना हुआ है।
फ़ायरवॉल परीक्षण एक नकारात्मक अभिकथन है — "यह पैकेट पार नहीं हुआ" — और एक नकारात्मक अभिकथन का कोई मूल्य नहीं है जब तक कि उपकरण के काम करने के बारे में ज्ञात न हो। एक ट्रेस मॉनिटर जो कभी कर्नेल से जुड़ा ही नहीं और एक फ़ायरवॉल जिसने सब कुछ अवरुद्ध कर दिया, बाइट-समान आउटपुट उत्पन्न करते हैं।
इसलिए NSE ऐसा निर्णय रिपोर्ट करने से इनकार करता है जिसे वह मापा हुआ नहीं दिखा सकता:
| गारंटी | तंत्र |
|---|---|
| मॉनिटर पहले टेस्ट पैकेट से पहले जुड़ा हुआ था | एक रेडीनेस कैनरी इंजेक्ट की जाती है और तब तक दोबारा इंजेक्ट की जाती है जब तक उसका कर्नेल ट्रेस न देख लिया जाए। कोई अवलोकन नहीं, तो कोई रन नहीं। |
| अंतिम पैकेट के बाद भी मॉनिटर अभी भी जुड़ा हुआ था | इंजेक्शन के बाद एक लाइवनेस कैनरी चलती है। यदि वह छूट जाए, तो वर्डिक्ट स्ट्रीम को काटा हुआ घोषित कर दिया जाता है। |
| पार्सर ने समझा कि कर्नेल ने क्या कहा | जिन ट्रेस पंक्तियों से कोई पैटर्न मेल नहीं खाता, उन्हें गिना जाता है, और शून्य से अधिक कोई भी गिनती डिबग लॉग के बजाय एक त्रुटि है। |
| मॉनिटर चुपचाप नहीं मरा | रीड लूप दर्ज करता है कि यह क्यों समाप्त हुआ — साफ़ स्टॉप, अप्रत्याशित EOF, टाइमआउट या क्रैश — और केवल साफ़ स्टॉप ही स्वीकार्य है। |
| अनुपस्थित वर्डिक्ट पास नहीं है | CLI रनर तब विफल होता है जब देखे गए वर्डिक्ट्स की संख्या अपेक्षित संख्या से भिन्न हो, किसी भी दिशा में। |
कैनरी पैकेट्स को ट्रेस आईडी द्वारा परिणामों से बाहर रखा जाता है, इसलिए वे कभी भी आपकी वर्डिक्ट स्ट्रीम में नहीं आते।
सूट यह दावा करने के बजाय सिद्ध करता है कि यह कायम रहता है: make test-blind पार्सर को
कुछ भी समझने के लिए मजबूर करता है, और बिल्ड तब तक विफल रहता है जब तक रनर
गैर-शून्य के साथ बाहर न निकले। वह जॉब हर पुश पर CI में चलता है।
nft monitor trace बताता है कि रूलसेट ने क्या निर्णय लिया। यह यह नहीं बता सकता कि
किसी इंटरफ़ेस से क्या निकला जिस पर रूलसेट ने कभी मेल नहीं खाया, जो वास्तव में वह प्रश्न है जो
शून्य-लीक दावा पूछता है। PCAPAsserter उसी को कवर करता है: एक AsyncSniffer
रैपर जो किसी नामित इंटरफ़ेस पर कैप्चर करता है और फ़्रेम वापस सौंपता है, ताकि एक टेस्ट
यह दावा कर सके कि किसी उद्दीपन ने कुछ भी नहीं उत्पन्न किया।
from nse import PCAPAsserter
asserter = PCAPAsserter(iface="veth-host")
await asserter.start()
# ... send the stimulus ...
leaked = await asserter.stop()
assert not leaked, leaked
वही नियम लागू होता है जो trace oracle पर लागू होता है, और इसे लागू करना कॉलर की ज़िम्मेदारी है: एक sniffer जो कभी attach ही नहीं हुआ और एक firewall जिसने सब कुछ block कर दिया, दोनों ही एक खाली सूची लौटाते हैं। stimulus को एक बार ruleset flush करके capture करें और frame के अभाव का दावा करने से पहले उसका देखा जाना आवश्यक करें।
डिफ़ॉल्ट filter link-local शोर को दबाता है, और कुछ नहीं।
DEFAULT_FILTER ARP और ICMPv6 प्रकार 133-137 को बाहर करता है - Neighbour Discovery, जो 255 का hop limit लेकर चलता है और किसी दूरस्थ observer तक नहीं पहुँच सकता। बाकी सब कुछ capture होता है, जिसमें वैश्विक रूप से routable पते पर भेजा गया ICMPv6 echo भी शामिल है। एक filter argument उस डिफ़ॉल्ट के साथ संयोजित होता है; replace_default_filter=True केवल आपके वाले का उपयोग करता है। यह escape hatch इसलिए मौजूद है क्योंकि filter BPF में compile होता है और kernel में evaluate होता है: जिस packet को वह बाहर कर देता है वह कभी userspace तक नहीं पहुँचता, इसलिए कोई भी consumer उसे downstream में पुनः प्राप्त नहीं कर सकता। 2.1.2 तक डिफ़ॉल्ट not arp and not icmp6 पढ़ता था, जो routable ICMPv6 को भी त्याग देता था - देखें
issue #14।