OpenVPN-এর পেছনে Docker ও VM ট্রাফিক: রুট নাকি পুনঃসংখ্যা?
OpenVPN ক্লায়েন্ট চালানো হোস্টের কন্টেইনার ও গেস্ট হয় রিটার্ন পাথ হারায়, নয়তো টানেল প্রিফিক্সের সঙ্গে সংঘর্ষে পড়ে। তিনটি প্রশ্ন সমাধান বেছে দেয়।
হোস্ট টানেল দিয়ে ব্রাউজ করে, অথচ পাশের কন্টেইনার কিছুই পৌঁছায় না। নিজের VPN ক্লায়েন্ট চালানো কন্টেইনার থেকে পোর্ট প্রকাশ করা আরও খারাপ: অনুরোধ পৌঁছায়, কিন্তু উত্তর কখনো বেরোয় না। দুটোই হোস্টের রাউটিং সিদ্ধান্ত, আর Docker শুধু বার্তাবাহক।
তিনটি প্রশ্ন ঠিক করে দেয় আপনি দুটির কোনটি দেখছেন, আর তাতে এক মিনিটের মতো লাগে।
একই রকম দেখতে দুটি ব্যর্থতা
প্রথমটি রিটার্ন-পাথের সমস্যা। প্রকাশিত পোর্টটি কন্টেইনারে অনূদিত হয়, অনুরোধ পৌঁছায়, আর উত্তরটি হোস্টের ডিফল্ট রুট দিয়ে পাঠানো হয়, যেটিকে OpenVPN ক্লায়েন্ট tun0-এর দিকে ঘুরিয়ে দিয়েছে। উত্তরটি এমন ঠিকানা থেকে বেরোয় যা দূরবর্তী পিয়ার প্রত্যাশা করে না, তাই তা বাদ পড়ে। দ্বিতীয়টি প্রিফিক্স সংঘর্ষ: Docker-এর ডিফল্ট ব্রিজ 172.17.0.0/16-এর মালিক, আর কর্পোরেট টানেল একই রেঞ্জ ঠেলে দেয়।
একটি ঠিক হয় রাউটিং টেবিল দিয়ে, অন্যটি ব্রিজের নাম্বার বদলে। কোনটি কোনটি জেনে রাখার আগেই সম্পাদনা করা মানে চলমান কন্টেইনার ভেঙে ফেলা।
তিনটি প্রশ্ন দিয়ে সিদ্ধান্ত নিন
প্রশ্ন এক: VPN বন্ধ করলে ব্যর্থতা কি মিলিয়ে যায়? টানেল বন্ধ থাকলে সব ঠিক চললে রিটার্ন পাথকে সন্দেহ করুন। প্রশ্ন দুই: ip route show table all কি একই প্রিফিক্স দুবার তালিকাভুক্ত করে, একবার ব্রিজে আর একবার tun0-এ? সেটাই সংঘর্ষ। প্রশ্ন তিন: ক্ষতিগ্রস্ত ঠিকানাটি কি কন্টেইনার, NAT গেস্ট নাকি ব্রিজড গেস্ট?
তৃতীয় প্রশ্নটি গুরুত্বপূর্ণ, কারণ প্রত্যেকের সঠিক সমাধান আলাদা, আর কন্টেইনারের সমাধান libvirt গেস্টে প্রয়োগ করলে একটা সন্ধ্যা নষ্ট হয়।
ip route
ip route show table all | grep -E '172\.1[7-9]|10\.8'
docker network inspect bridge --format '{{.IPAM.Config}}'রিটার্ন পাথ: একটি সোর্স ঠিকানার জন্য টেবিল
যখন কন্টেইনারের ট্রাফিককে ফিজিক্যাল ইন্টারফেস দিয়ে বেরোতে হবে, অথচ হোস্ট নিজে টানেল ব্যবহার করে, তখন সবচেয়ে ছোট পরিবর্তন হলো সোর্স-ভিত্তিক রাউটিং। কন্টেইনারের ঠিকানার সঙ্গে মেলে এমন একটি নিয়ম যোগ করুন এবং তা একটি নির্দিষ্ট টেবিলে পাঠান। হোস্টে আর কিছুই নড়ে না।
ip rule add from 172.22.0.3 lookup 10
ip route add default via 172.22.0.1 table 10যে প্যাকেটের সোর্স ওই ঠিকানা, তা আগে টেবিল 10 দেখে, আর টেবিল 10 তা টানেলের বদলে ব্রিজ গেটওয়েতে পাঠায়।
যাচাই করুন ip route get 1.1.1.1 from 172.22.0.3 দিয়ে। উত্তরে ব্রিজ ইন্টারফেসের নাম থাকতে হবে, tun0 নয়। এভাবে যোগ করা নিয়ম রিবুটে হারিয়ে যায়, তাই সেগুলো কন্টেইনারের মালিকানা রাখা unit বা নেটওয়ার্ক হুকে রাখুন।
একই প্যাটার্ন WireGuard কন্টেইনারেও কাজ করে, যেখানে রিপ্লাই পাথেও একটি স্পষ্ট নিয়ম দরকার।
প্রিফিক্স সংঘর্ষ: ব্রিজের নাম্বার বদলান
একটি রুট টেবিল একটি প্রিফিক্সকে এক জায়গায় পাঠায়। VPN যদি 172.17.0.0/16 ঠেলে দেয় আর Docker-এর ব্রিজ আগেই সেখানে থাকে, তবে কম মেট্রিক জেতে: Docker তার সংযুক্ত রুট মেট্রিক 0-এ বসায়, আর ঠেলে দেওয়া রুট আসে 50-এ। তখন Docker চলতে থাকলেও টানেল ভাঙা দেখায়, কিংবা উল্টোটা, ইনস্টলেশনের ক্রম অনুযায়ী। মেট্রিকের সঙ্গে লড়াই না করে ব্রিজের নাম্বার বদলান।
{
"bip": "10.200.0.1/24",
"default-address-pools": [{"base": "10.201.0.0/16", "size": 24}]
}পরিবর্তনের পর Docker পুনরায় চালু করুন এবং পুরোনো পুল দিয়ে তৈরি নেটওয়ার্কগুলো আবার তৈরি করুন। বদলে মেট্রিক বদলালে সংঘর্ষ কেবল পরের বুটে সরে যায়।
VM-দের আবার অন্য উত্তর দরকার
ডিফল্ট NAT নেটওয়ার্কে থাকা libvirt গেস্ট হোস্টের রাউটিং উত্তরাধিকার করে, আর হোস্টের টানেল ডিফল্ট রুটের মালিক হওয়ামাত্রই বাইরে পৌঁছানো বন্ধ করে দেয়। গেস্টটিকে ব্রিজড বা macvtap ডিভাইসে সরালে তা ফিজিক্যাল নেটওয়ার্কে নিজের পথ পায়। virt-manager-এ হার্ডওয়্যার যোগ করুন, Network বেছে নিন, সোর্স হিসেবে macvtap হোস্ট ডিভাইস দিন, মডেল হিসেবে virtio রাখুন, তারপর পুরোনো NAT ইন্টারফেস নিষ্ক্রিয় করুন।
macvtap গেস্ট সাধারণত নিজের হোস্টে পৌঁছাতে পারে না। এটি ত্রুটি নয়, প্রত্যাশিত আচরণ, আর তা আপনার রেখে যাওয়া নোটে থাকা উচিত।
যে গেস্টের কেবল হোস্টের LAN দরকার, তার জন্য ভেন্ডরের ক্লায়েন্টে অনুপস্থিত সুইচটি থাকতে পারে: Mullvad-এ mullvad lan set allow libvirt স্পর্শ না করেই স্থানীয় পৌঁছানো পুনরুদ্ধার করে। আর যখন কোনো কন্টেইনারকে কেবল টানেল দিয়েই পৌঁছানো যায় এমন হতে হবে, প্রকাশিত পোর্টটি টানেল ঠিকানায় বাঁধুন, -p 10.8.0.5:8080:8080, প্রতিটি ঠিকানায় প্রকাশ করার বদলে।