एक ही Linux होस्ट पर दूसरा OpenVPN क्लाइंट जोड़ना दो में से एक जगह पर विफल होता है। या तो अंदर का क्लाइंट अपने सर्वर तक नहीं पहुँच पाता क्योंकि बाहरी टनल ने वह ट्रांसपोर्ट पकड़ लिया है, या दूसरा क्लाइंट रूट टेबल फिर से लिख देता है और पहली टनल काम करना बंद कर देती है। दोनों समस्याएँ रूटिंग में हैं, एन्क्रिप्शन में नहीं, और दोनों नई टनल के कोई भी एप्लिकेशन ट्रैफ़िक ले जाने से पहले हल हो जाती हैं। यहाँ पते उदाहरण के लिए हैं: tun0 बाहरी टनल है, 203.0.113.9 अंदर का सर्वर है, और TCP 9999 वह फ़्लो है जिसे अंदर का रास्ता इस्तेमाल करना चाहिए।

विफलता के दो तरीके, एक रूट टेबल

अंदर का क्लाइंट अपने सर्वर की ओर UDP सॉकेट खोलता है, और वह सॉकेट किसी भी अन्य की तरह मौजूदा रूट टेबल का अनुसरण करता है। अगर बाहरी टनल के पास पहले से डिफ़ॉल्ट है, तो हैंडशेक पैकेट बाहरी टनल में चले जाते हैं। यह तभी काम करता है जब बाहरी सर्वर अंदर के सर्वर तक पहुँच सके और दूसरा पक्ष फ़्लो को ले जाने पर सहमत हो; वरना हैंडशेक अटक जाता है और क्लाइंट फिर कोशिश करता है।

दूसरी विफलता सर्वर पुश से आती है। सामान्य पुश redirect-gateway def1 है, जो डिफ़ॉल्ट रूट बदलने के बजाय 0.0.0.0/1 और 128.0.0.0/1 इंस्टॉल करता है। इसलिए जो दो क्लाइंट अपना-अपना /1 जोड़ा इंस्टॉल करते हैं वे टकराते हैं, और लगभग हर गंतव्य के लिए नवीनतम जोड़ा जीतता है। जब दूसरे के जुड़ने के बाद टनल मर जाए तो टेबल में उन दो प्रीफ़िक्स को देखें, क्योंकि हो सकता है डिफ़ॉल्ट रूट खुद कभी बदला ही न हो।

फ़्लो को मार्क करें और उसे एक टेबल दें

चुने हुए ट्रैफ़िक को mangle टेबल में मार्क करके और पॉलिसी नियम में उस मार्क से मिलान करके दिशा दें। नियम एक समर्पित टेबल की ओर इशारा करता है जिसका डिफ़ॉल्ट रूट अंदर का डिवाइस है, इसलिए केवल मार्क किए गए पैकेट ही अंदर का रास्ता लेते हैं।

iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200

इस नियम सेट में ज़्यादातर विफलताएँ दो गलतियों से आती हैं। फ़ायरवॉल जो मार्क मान सेट करता है और नियम जिस मान से मिलान करता है, वे एक जैसे ही होने चाहिए, क्योंकि बेमेल कोई त्रुटि और कोई प्रभाव नहीं देता। और PREROUTING केवल बाहर से आने वाले पैकेट देखता है, इसलिए इस होस्ट पर शुरू हुए कनेक्शन को मार्क होने से पहले उसी मिलान वाले OUTPUT नियम की ज़रूरत होती है।

दूसरे क्लाइंट से रूट का स्वामित्व छीनें

दो विकल्प दूसरे क्लाइंट को टेबल संपादित करने से रोकते हैं, और वे अलग-अलग बिंदुओं पर काम करते हैं। route-nopull पुश किए गए रूट विकल्पों को अनदेखा करता है, इसलिए कुछ भी इंस्टॉल नहीं होता। route-noexec पुश किए गए विकल्पों को क्लाइंट के वातावरण में स्वीकार करता है पर टेबल परिवर्तन हुक पर छोड़ देता है, और यही आप तब चाहते हैं जब आपको देखना हो कि सर्वर ने क्या पेश किया।

हुक अपने वातावरण में पुश किए गए मानों के साथ चलता है, और उसे केवल वही प्रविष्टियाँ जोड़नी चाहिए जिन्हें आपने स्वीकृत किया। इसे idempotent बनाएँ: फिर से बनाने से पहले उस टेबल को खाली करें जिसका वह मालिक है, और यह न मानें कि पिछले रन ने साफ़ स्थिति छोड़ी थी। फिर से कनेक्ट होने पर हुक फिर चलता है, और बिना साफ़ किए जोड़ने वाला हुक डुप्लिकेट रूट जमा करता है।

एक मालिक चुनें और उसे लिख लें। जो प्रोफ़ाइल दोनों विकल्प सेट करती है, या जो हुक मैन्युअल स्क्रिप्ट से प्रतिस्पर्धा करता है, वह ऐसी टेबल बनाता है जिसे बाद में कोई समझा नहीं सकता।

दोनों सर्वर पते पिन करें

अंदर के क्लाइंट के कनेक्ट होने से पहले अंदर के सर्वर को बाहरी डिवाइस से होकर होस्ट रूट चाहिए। वही प्रविष्टि अंदर के ट्रांसपोर्ट को बाहरी टनल के भीतर रखती है, उसे डिफ़ॉल्ट का अनुसरण करने देने के बजाय।

ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9

मुख्य टेबल में बाहरी सर्वर के लिए भी मिलता-जुलता होस्ट रूट जोड़ें, वरना फिर से कनेक्ट होने पर बाहरी क्लाइंट का अपना ट्रांसपोर्ट उसकी अपनी टनल में रूट हो सकता है। क्रम वैकल्पिक नहीं है: ये प्रविष्टियाँ संबंधित इंटरफ़ेस बनने के बाद जोड़ें, यानी ऐसा हुक या स्क्रिप्ट जो कनेक्ट के बाद चले। बंद डिवाइस की ओर इशारा करता रूट हटा दिया जाता है या अनदेखा कर दिया जाता है, इसलिए बूट के समय लिखी प्रविष्टि उस क्रम में नहीं टिकती जिसकी आपने कल्पना की थी।

पूरी टेबल पढ़ने के बजाय लुकअप जाँचें। रूट लुकअप का आउटपुट वह डिवाइस और स्रोत पता बताता है जिसे kernel इस्तेमाल करेगा, और क्लाइंट अपना सॉकेट खोलते समय ठीक वही पाता है।

श्रृंखला जाँचें और विफलता को दिखने लायक बनाएँ

अंदर का क्लाइंट कनेक्ट होते समय बाहरी इंटरफ़ेस पर कैप्चर करें। अंदर का हैंडशेक बाहरी टनल के भीतर एन्क्रिप्टेड पेलोड के रूप में दिखना चाहिए; अगर वह 203.0.113.9 की ओर सादे UDP के रूप में दिखे, तो होस्ट रूट गायब है और श्रृंखला कभी बनी ही नहीं।

जो श्रृंखला चुपचाप भौतिक अपलिंक पर लौट जाती है, वह सबसे बुरा परिणाम है, क्योंकि इंटरफ़ेस की स्थिति कुछ नहीं बताती और अंदर का ट्रैफ़िक गलत स्रोत पते से निकलता है। अगर बाहरी टनल गिरने पर दूसरा क्लाइंट सीधे फिर से कनेक्ट कर सकता है, तो उस रास्ते को बंद करें या उसे बाहरी इंटरफ़ेस से बाँधें ताकि विफलता दिखे।

दो फ़्लो और एक नियम डंप के साथ समाप्त करें: मार्क किया गया और बिना मार्क वाला कनेक्शन अलग रास्ते लेना चाहिए, और ip rule show को वह प्राथमिकता सूचीबद्ध करनी चाहिए जो आप चाहते थे। अगर दोनों फ़्लो एक ही रास्ता लेते हैं, तो मार्क वहाँ लागू नहीं हो रहा जहाँ आप सोचते हैं।

संबंधित लेख