কেউ চায় ব্রাউজারটি টানেল ব্যবহার করুক, আর জবাবে ফিরে আসে গন্তব্য পোর্ট 80 ও 443-এর সাথে মেলা একটি ফায়ারওয়াল নিয়ম। এটি নির্ভুল দেখায়, কিন্তু নয়। পোর্ট মিল প্যাকেট বেছে নেয় তাদের পরিবহন হেডার দিয়ে, কোন প্রোগ্রাম সকেট খুলেছে তা দিয়ে নয়, আর আধুনিক ব্রাউজিং TCP-তে ওই দুটি পোর্টেই নিজেকে সীমাবদ্ধ রাখে না। নিয়মটি আপনার অন্তর্ভুক্ত করতে চাওয়া কিছু ট্রাফিক মিস করবে এবং আপনি কখনো স্পর্শ করতে চাননি এমন ট্রাফিক ধরবে। এটি লেখার আগে ঠিক করুন তিনটি ভিন্ন সীমার মধ্যে আসলে কোনটি চান।

নিয়মটি একটি পরিবহন শ্রেণি বর্ণনা করে, কোনো অ্যাপ্লিকেশন নয়

Linux-এ গন্তব্য-পোর্ট মিল TCP হেডার দেখে, তার উপরের কিছু নয়। ওই প্যাকেটগুলো চিহ্নিত করে নীতি-রুট দিয়ে চালানো ঠিক নথিভুক্ত মতোই কাজ করে, আর ওই যন্ত্রের কিছুই জানে না পেলোডের অর্থ কী বা কোন প্রসেস এটি পাঠিয়েছে। চিহ্ন হলো প্যাকেটে লাগানো একটি সংখ্যা, অ্যাপ্লিকেশনে লাগানো কোনো পরিচয় নয়।

nft add rule inet mangle output tcp dport { 80, 443 } meta mark set 0x1
ip rule add fwmark 0x1 table 100
ip route add default dev wg0 table 100

সঙ্গে সঙ্গে দুটি পরিণতি আসে। যে সফটওয়্যার আপডেটার TCP 443-এ যোগাযোগ করে, সে ব্রাউজারের মতোই আচরণ পায়, যা হয়তো ঠিক আছে, নয়তো পরের আপডেট চক্রের জন্য অপেক্ষারত একটি বিভ্রাট। আর ইচ্ছাকৃতভাবে অন্য পোর্টে, ধরা যাক 8443-এ প্রকাশিত একটি ওয়েব সেবা সম্পূর্ণ নিয়মের বাইরে পড়ে, যদিও সেটিই ব্যবহারকারীর যত্নের ওয়েব ট্রাফিক।

সংখ্যাগুলো বৈধ নির্বাচক যখন প্রয়োজনটা সত্যিই ওই পোর্টগুলো নিয়ে। তারা কল্পকাহিনি হয়ে ওঠে যখন টিকিটে «ব্রাউজার» লেখা থাকে আর নিয়মসমূহে পোর্ট-পরিসর বাস্তবায়িত হয়। এই ফাঁকটা নথিকরণের সৌখিনতা নয়। এটি হলো একটি নিয়মের মধ্যে পার্থক্য যা আপনি পর্যালোচনায় রক্ষা করতে পারেন আর একটি যা কেউ পরীক্ষা করতে পারে না।

HTTP/3 চুপচাপ আপনার TCP নিয়মটি পাশ কাটিয়ে যায়

HTTP/3 চলে QUIC-এর ওপর, আর QUIC UDP-তে বহন করা হয়। কেবল TCP-এর সাথে মেলা নিয়ম এটি দেখতে পায় না, তাই যে ব্রাউজার আপনার পরীক্ষা পাতা পূরণ করে, সে-ই পরে একটি অনুরোধ UDP-তে পাঠিয়ে টানেল পাশ কাটাতে পারে, কেউ কোনো সেটিং না বদলেই। RFC 9114 HTTP/3-কে QUIC-ভিত্তিক প্রোটোকল হিসেবে বর্ণনা করে, আর সাধারণ স্থাপনায় QUIC UDP ব্যবহার করে যার ডিফল্ট পোর্ট 443।

কোনো ব্রাউজার HTTP/3 চেষ্টা করবে কি না তা নির্ভর করে তার কনফিগারেশন, সাইট, এবং আগের কোনো চেষ্টা সফল হয়েছে কি না তার ওপর। এতে মুখস্থ থেকে বিচার করা মুশকিল। বরং টুলটিকেই জিজ্ঞাসা করুন:

curl --http3 -sS -o /dev/null -w '%{http_version} %{time_total}\n' https://example.com
ss -tunp | grep -E ':443\b'

curl লাইনটি যে সংস্করণে সম্মত হয়েছে তা ছাপে, তাই 3 নিশ্চিত করে যে UDP পথ ব্যবহার হয়েছে। এরপর সকেট তালিকা দেখায় ওই সংযোগটি টানেল ইন্টারফেসে বাঁধা না ভৌত ইন্টারফেসে। যদি আপনার curl বিল্ডে HTTP/3 না থাকে, ফ্ল্যাগটি চুপচাপ পিছিয়ে না গিয়ে জোরে ব্যর্থ হয়, যা তার নিজস্ব ছোট্ট দয়া।

DNS একটি আলাদা সিদ্ধান্ত, যা আপনাকে নিতে হবে

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

এটি স্পষ্টভাবে ঠিক করুন। যদি অভ্যন্তরীণ নাম টানেল দিয়ে সমাধান হওয়া দরকার হয়, রিজলভারকে তার ভেতরে থাকতে হবে, আর নিয়মসমূহকে ওই রিজলভারে DNS অনুমোদন করতে হবে এবং অন্য কোয়েরি বাইরে রাখতে হবে। যদি ব্রাউজার কোনো পাবলিক প্রদানকারীর কাছে DNS over HTTPS ব্যবহার করে, কোয়েরিটি আপনার রিজলভারকে পুরোপুরি পাশ কাটায় আর পোর্ট-নিয়ম কোনো সাহায্য করতে পারে না। পছন্দটি রাউটিং নিয়মের সঙ্গে একই পরিবর্তন-রেকর্ডে লিখুন, কারণ পরের ব্যর্থতা যিনিই ডিবাগ করবেন তিনি দুটো একসাথেই পড়েন।

তারপর পাতা দিয়ে নয়, রিজলভার দিয়ে যাচাই করুন:

resolvectl query intranet.example.internal
resolvectl status | grep -A3 'Current DNS Server'

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

তিনটি সীমা, তিনটি ভিন্ন কৌশল

আপনি যে সীমা চান তার নাম দিলেই বেশিরভাগ বিভ্রান্তি মিলিয়ে যায়। এগুলো বিনিময়যোগ্য নয়, আর টানেল বিভ্রাটের সময় প্রত্যেকের ব্যর্থতার ধরন আলাদা।

What you actually wantMechanism that fitsWhat it does not cover
These transport ports use this exitFirewall mark plus policy routeApplications, HTTP/3 over UDP, DNS
This browsing session stays separateApplication-aware VPN, or a separate network namespace plus a proxyOther applications in the same session
Only these private sites are reachableDestination-based routes with private DNSPublic sites on the same address family

আলাদা ব্রাউজার প্রোফাইল হলো মাঝের সারির ফাঁদ। এটি কুকি ও ইতিহাস আলাদা করে, আর হোস্টের রাউটিং টেবিলে কিছুই বদলায় না, তাই দুটি প্রোফাইলই একই পথ নেয়। বিচ্ছিন্নতার জন্য দরকার কার্নেল যা প্রয়োগ করে, অর্থাৎ নেমস্পেস, কনটেইনার, বা নিজের টানেল ইন্টারফেসের মালিক একটি অ্যাপ্লিকেশন।

যেই সারি প্রযোজ্য হোক, টানেল পড়ে গেলে কী হওয়া উচিত তা লিখে রাখুন। ইন্টারফেসের সঙ্গে হারিয়ে যাওয়া চিহ্ন-ভিত্তিক রুট সাধারণত ভৌত ডিফল্ট রুটে ফিরে যায়, যা fail-open আচরণ। ব্রাউজিংয়ের জন্য এটি গ্রহণযোগ্য হতে পারে, অন্য কিছুর জন্য নয়, আর এটি একটি সিদ্ধান্ত, বাস্তবায়নের খুঁটিনাটি নয়।

আপনি যে প্রবাহ ঢাকার দাবি করেন, সেগুলো পরীক্ষা করুন

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

ip route get 203.0.113.40
curl -sS -o /dev/null -w 'v4 %{http_version} %{remote_ip}\n' https://example.com
nft list ruleset | grep -A2 'dport'

রুট অনুসন্ধান জানায় একটি গন্তব্য আসলে কোন ইন্টারফেস ব্যবহার করে, আর এটিই সেই তথ্য যা বেশিরভাগ প্রতিবেদনে ভুল হয়। curl লাইন সম্মত সংস্করণ ও ঠিকানা-পরিবার নিশ্চিত করে। নিয়মতালিকার ডাম্প ধরে ফেলে পরীক্ষার সময় যোগ করা এবং সীমা নির্ধারণ করতে ভুলে যাওয়া নিয়মটি, আর এভাবেই অস্থায়ী চিহ্ন স্থায়ী fail-open রাউটিংয়ে পরিণত হয়।

তিনটি আউটপুটই সময়-সহ নথিভুক্ত করুন এবং পরিবর্তনের সঙ্গে রাখুন। পরে কেউ যখন জানায় যে «VPN ইন্ট্রানেট ভেঙে দিয়েছে», তখন অভীষ্ট সীমা আর বাস্তবায়িত সীমার পার্থক্য ওই রেকর্ডে দেখা যাবে, আর সমাধান হবে নিয়ম বদল, বিতর্ক নয়।

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