এই ওয়ার্কস্টেশন থেকে বেরোনোর একটি পথ SOCKS প্রক্সি, আর তার পেছনে OpenVPN কোনো কাজের বিবরণ ছাড়াই কানেক্ট টাইমআউট জানায়। একই মেশিনের ব্রাউজার ওই প্রক্সি দিয়ে কাজ করে, ক্রেডেনশিয়াল ঠিক আছে, আর পোর্ট সাড়া দেয়। তিনটি জিনিস এতটাই আলাদা যে আগে দেখতে হয়: প্রক্সি যে SOCKS সংস্করণ বলে, ক্লায়েন্ট যে ট্রান্সপোর্ট বেছেছে, এবং নাম বিশ্লেষণ যেখানে ঘটে। ফায়ারওয়ালকে দোষী ভাবার আগে এগুলোর প্রতিটি নিশ্চিত করুন।

ফায়ারওয়ালের আগে SOCKS সংস্করণ মিলান

কমিউনিটি OpenVPN socks-proxy-এর জন্য SOCKS5 বলে। এটিকে এমন প্রক্সিতে লাগান যা কেবল SOCKS4 দেয়; TCP সংযোগ খোলে, তারপর থেমে যায়, কারণ ক্লায়েন্ট এমন অভিবাদনের উত্তর প্রতীক্ষা করে যা অন্য প্রান্ত কখনো বিশ্লেষণ করে না। বাইরে থেকে এই থেমে যাওয়া হুবহু ফিল্টার করা পোর্টের মতো দেখায়, এজন্যই সংস্করণের প্রশ্ন যেকোনো ফায়ারওয়াল নিয়মের আগে আসে। SOCKS-সচেতন একটি ফেচ এক কমান্ডেই বিষয়টি ঠিক করে।

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example

সম্পূর্ণ অনুরোধ একসঙ্গে দুটি বিষয় প্রমাণ করে: প্রক্সি SOCKS অনুরোধ গ্রহণ করেছে এবং সে নামটি বিশ্লেষণ করেছে। কোনো URL স্কিম দরকার নেই, কারণ curl খালি হোস্টকে HTTP ধরে, আর এটি এই পরীক্ষার জন্য যথেষ্ট।

এই ফেচ ক্লায়েন্ট লগ যে ব্যর্থতা লুকায় তাও বাদ দেয়। প্রক্সি ব্রাউজারকে অনুমতি দিয়েও VPN গন্তব্য প্রত্যাখ্যান করতে পারে, তখন প্রত্যাখ্যান ঘটে CONNECT-এ, যেকোনো VPN প্রমাণীকরণের আগে। OpenVPN কেবল টাইমআউট জানায়, তাই প্রক্সির নিজের উত্তরই আপনার প্রয়োজনীয় প্রমাণ।

ট্রান্সপোর্ট দুই দিকেই TCP হতে হবে

SOCKS5 এখানে TCP স্ট্রিম বহন করে, তাই সুড়ঙ্গের নিজেরই proto tcp-client দরকার। যে প্রোফাইল এখনো UDP-তে সেট আছে সেটি এই পথে কাজ করবে না, কারণ ক্লায়েন্ট প্রোটোকলের UDP অ্যাসোসিয়েশন মোড ব্যবহার করে না। প্রোফাইল উল্টানো প্রকৃত পরিবর্তন, আনুষ্ঠানিকতা নয়: দূর প্রান্তকে একই পোর্টে TCP-তে শুনতে হবে। এরপর পেলোড TCP-র ভিতরে TCP হয়ে যায়, যেখানে হারানো সেগমেন্ট দুবার পুনঃপ্রেরিত হয় ও গতি কমে, আর ইন্টারঅ্যাকটিভ সেশন এটি বড় স্থানান্তরের চেয়ে অনেক বেশি টের পায়।

proto tcp-client
remote gw.lab.example 8443
socks-proxy 127.0.0.1 9050

এই নির্দেশটি প্রক্সি হোস্ট, ঐচ্ছিক পোর্ট ও ঐচ্ছিক ক্রেডেনশিয়াল ফাইল নেয়। সেগুলো প্রোফাইলের ভিতরেই রাখুন যাতে অন্যত্র রাখা কপি একই আচরণ করে।

পুরো চেইনকে একটি কনটেইনারে সীমাবদ্ধ করুন

হোস্টে চেইন করা মানে তার ডিফল্ট রুট দখল করা আর resolver-কে এমন অবস্থায় রেখে দেওয়া যা পরে কেউ ব্যাখ্যা করতে পারবে না। নামস্থান বা কনটেইনার বরং এটিকে সীমাবদ্ধ করে, তাই হোস্ট নিজের পথ রাখে আর SOCKS হপ ও সুড়ঙ্গ একসঙ্গে থাকে। ভিতরে কিছুই সুড়ঙ্গ ডিভাইস, সেই ডিভাইস কনফিগার করার অধিকার ও পৌঁছনোযোগ্য প্রক্সি ছাড়া ওঠে না। Compose সার্ভিস এটি পায় cap_add: NET_ADMIN আর bind-মাউন্ট করা /dev/net/tun দিয়ে।

cap_add:
  - NET_ADMIN
devices:
  - /dev/net/tun:/dev/net/tun

এই জোড়া কনটেইনারকে privileged চালানোর চেয়ে সংকীর্ণ, এবং ডিভাইসে প্রবেশের পুরো প্রয়োজন এটুকুই। Tor ক্লায়েন্ট বা আলাদা প্রক্সি কনটেইনার শ্রোতা জোগাতে পারে। দুই ক্ষেত্রেই এটি loopback-এ বাঁধুন, আর প্রক্সিকে নেটওয়ার্কে উন্মুক্ত না করে নামস্থান থেকে হোস্টের মধ্য দিয়ে এতে পৌঁছান।

নাম বিশ্লেষণই সেই জায়গা যেখানে বিচ্ছিন্নতা ব্যর্থ হয়

যে সুড়ঙ্গ প্যাকেট বহন করে অথচ হোস্টের resolver-কে জিজ্ঞাসা করে সে কিছুই আলাদা করেনি। দুটি জিনিস বিচ্ছিন্নতাকে সত্যিকারের করে: নামস্থানের নিজের resolver থাকা, আর তার কোয়েরিগুলো প্রক্সি বা সুড়ঙ্গ দিয়ে যাওয়া, কখনো ভৌত ইন্টারফেস দিয়ে নয়। পরীক্ষার জন্য দুটি নাম নিন: একটি যা কেবল সুড়ঙ্গের পেছনে আছে, আর একটি সর্বজনীন যা একই পথ নেওয়া উচিত।

docker compose exec vpn cat /etc/resolv.conf
docker compose exec vpn getent hosts internal.lab.example

যদি দূরের নাম বিশ্লেষিত হয় আর সর্বজনীনটি না হয়, তবে চেইন বাছাইমূলক, ভাঙা নয়, আর পার্থক্য বলে দেয় প্রতিটি কোয়েরি কোন পথ নিয়েছে। যদি দুটোই হোস্ট থেকে বিশ্লেষিত হয় কিন্তু কনটেইনারের ভিতরে কোনোটিই না হয়, তবে কনটেইনার এখনো হোস্টের resolver ধার করছে। যে resolver ফাইল পেলেন তা লিখে রাখুন, কারণ ওই সেটিংটাই বদলাতে হবে।

প্রতিটি হপ ক্রমে প্রমাণ করুন

তালিকাটি ছোট। একটি SOCKS5 অনুরোধ উত্তর পায়, সুড়ঙ্গ প্রক্সির মধ্য দিয়ে তার শ্রোতার কাছে পৌঁছায়, আর নামস্থান থেকে বেরোনো প্যাকেট সেই ঠিকানা বহন করে যা দূর প্রান্ত প্রত্যাশা করে। আরও কনফিগারেশন চাপানোর বদলে প্রতিটি আলাদাভাবে নিশ্চিত করুন। ক্লায়েন্ট যখন বলে সংযুক্ত আর কিছুই নড়ে না, তখন ভাঙন প্রায় সবসময় দ্বিতীয় বা তৃতীয় তথ্যে থাকে।

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example
docker compose exec vpn ip route get 203.0.113.10
docker compose exec vpn getent hosts internal.lab.example

যে সমন্বয় কাজ করেছে তা লিখে রাখুন: SOCKS সংস্করণ, ট্রান্সপোর্ট, resolver ও নামস্থান সেটিংস। এই চেইনটি দ্বিতীয়বার স্মৃতি থেকে সমাধান করা নোটের চেয়ে বেশি খরচ। ওই চারটি তথ্য টিকিটে রাখুন, চ্যাট থ্রেডে নয়।

যে চেইন সংযুক্ত বলে জানায় অথচ কিছুই পার করে না, সেটি সাধারণত যে হপটি আপনি এখনো প্রমাণ করেননি সেখানেই ব্যর্থ হয়েছে। আরেকটি স্তর যোগ করার আগে সেই হপটি পরীক্ষা করুন।

সম্পর্কিত নিবন্ধ