WireGuard-এ DNS ঠিক করুন: 3টি সাধারণ ব্যর্থতা
WireGuard tunnel চালু, কিন্তু নাম resolve হচ্ছে না বা DNS query local router-এ leak হচ্ছে? তিনটি failure mode শনাক্ত করে routing ও resolver সেটিং ঠিক করুন।
WireGuard tunnel চালু হওয়ার সঙ্গে সঙ্গে DNS কেন কাজ করা বন্ধ করে
WireGuard-এর মাধ্যমে DNS তিনভাবে ব্যর্থ হয়, এবং প্রতিটির আলাদা সমাধান আছে। কোনো নামই resolve হয় না, অথবা নাম resolve হলেও query tunnel-এর বাইরে আপনার মেশিন থেকে পাঠানো হয়, অথবা interface চালু হওয়ার কয়েক সেকেন্ড পর client-এর নিজস্ব resolver manager সেটিংটি overwrite করে। Tunnel প্রায় কখনোই সমস্যার কারণ নয়। সমস্যা হলো client-কে কোন resolver-কে জিজ্ঞাসা করতে হবে তা জানানো সেই এক লাইন এবং সেই resolver-এ packet কীভাবে যাবে তা নির্ধারণ করা routing।
WireGuard IP packet পাঠায় এবং DNS (domain name system, example.com-এর মতো নামকে IP address-এ রূপান্তরকারী service) সম্পর্কে কিছুই জানে না। Client-এর [Interface] block-এর DNS = line কোনো WireGuard setting নয়। এটি interface চালু করা shell wrapper wg-quick পড়ে, এবং tunnel চালু থাকা অবস্থায় wg-quick client-এর resolver configuration সম্পাদনা করে; tunnel বন্ধ হলে wg-quick down সেটি আগের অবস্থায় ফিরিয়ে দেয়। তাই নিচের প্রতিটি সমস্যা হয় routing সমস্যা, নয়তো wg-quick সমস্যা; এটি কখনো cryptography সমস্যা নয়। Tunnel এখনো তৈরি না হলে আগে নিজের VPS-এ self-hosted WireGuard VPN সেট আপ করুন। এরপর এই পৃষ্ঠায় ফিরে আসুন।
DNS নিয়ে কাজ করার আগে tunnel সুস্থ আছে কি না নিশ্চিত করুন।
sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1wg show-এ সাম্প্রতিক latest handshake-সহ peer দেখানো উচিত, এবং উভয় ping-এর উত্তর পাওয়া উচিত। ping 1.1.1.1 timeout হলে এটি DNS সমস্যা নয়, বরং forwarding বা NAT (network address translation) সমস্যা; resolver config যতই পরিবর্তন করুন, তাতে সমাধান হবে না। Ping-এর উত্তর পাওয়া গেলেও প্রকৃত traffic শুরু হলে throughput কমে গেলে সেটি আলাদা সমস্যা। এই পৃষ্ঠার কোনো বিষয়ের কারণে নয়, ধীর WireGuard-এর কারণ প্রায় সবসময় MTU। এখানে প্রতিটি উদাহরণে tunnel subnet হিসেবে 10.8.0.0/24 এবং server-এর tunnel address হিসেবে 10.8.0.1 ব্যবহার করা হয়েছে। আপনার নিজস্ব মান বসান।
ব্যর্থতা এক: কোনো কিছুই resolve হয় না, কারণ resolver কখনও উত্তর দেয় না
লক্ষণটি নির্দিষ্ট। ping 1.1.1.1 কাজ করে, আর curl https://example.com এটি ফেরত দেয়:
curl: (6) Could not resolve host: example.comclient থেকে সরাসরি tunnel resolver-কে জিজ্ঞাসা করুন। Ubuntu এবং Debian-এ dig কমান্ডটি dnsutils package থেকে আসে।
dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.comপ্রথম command একটি address ফেরত দেয়। এতে প্রমাণ হয় যে tunnel-এর মাধ্যমে packet Internet-এ পৌঁছাচ্ছে। দ্বিতীয়টি কিছু ফেরত দেয় না এবং ;; communication timed out; no servers could be reached প্রিন্ট করে। পুরো diagnosis এটাই: আপনার client-কে 10.8.0.1 ব্যবহার করার জন্য সেট করা আছে, কিন্তু 10.8.0.1 UDP port 53-এ উত্তর দিচ্ছে না।
এর দুটি কারণ হতে পারে। Server-এ কোনো resolver চালু নেই, অথবা query server-এ পৌঁছানোর আগেই server firewall সেটি drop করছে। Server-এ উভয় বিষয় পরীক্ষা করুন।
sudo ss -ulnp | grep ':53'
sudo nft list rulesetচালু থাকা এবং সঠিকভাবে bind করা resolver-এর output-এ 10.8.0.1:53 অথবা 0.0.0.0:53-সহ একটি line দেখা যায়। Ubuntu-তে সাধারণত সমস্যা হয় 127.0.0.53:53 নিয়ে। এটি systemd-resolved-এর stub listener, যা একটি loopback address-এ bind করে এবং ইচ্ছাকৃতভাবে অন্য machine থেকে unreachable থাকে। যে server-এ একমাত্র resolver হিসেবে এই stub চালু আছে, তার দিকে VPN client নির্দেশ করলে ঠিক এই timeout দেখা যায়।
সমাধান হলো এমন একটি resolver ব্যবহার করা, যা tunnel address-এ listen করে। পাশাপাশি peers যাতে সেখানে পৌঁছাতে পারে, তার জন্য একটি firewall rule যোগ করতে হবে।
sudo apt update && sudo apt install -y unbound
printf 'server:\n interface: 10.8.0.1\n access-control: 10.8.0.0/24 allow\n' \
| sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'এরপর শুধু tunnel traffic-এর জন্য port খুলুন। nftables ব্যবহার করলে /etc/nftables.conf-এ থাকা input chain-এ এই দুটি line যোগ করুন এবং sudo systemctl reload nftables দিয়ে reload করুন।
udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" acceptufw ব্যবহার করলে sudo ufw allow in on wg0 to any port 53 একই কাজ করে। Public Internet-এর জন্য কখনও port 53 খুলবেন না। খোলা recursive resolver কয়েক দিনের মধ্যেই scanner-রা শনাক্ত করে এবং denial-of-service attack বাড়াতে ব্যবহার করে। আপনি জানার আগেই আপনার provider সেই traffic শনাক্ত করতে পারে।
client থেকে dig +short @10.8.0.1 example.com আবার চালান। Output-এ একটি address দেখা গেলে resolver path কাজ করছে। এখন client-কে শুধু সেটি ব্যবহার করতে হবে। client-এর [Interface] block-এ line-টি যোগ করুন এবং sudo wg-quick down wg0 && sudo wg-quick up wg0 দিয়ে interface restart করুন।
[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1ব্যর্থতা দুই: DNS leak, কারণ split tunnel resolver-এর ট্রাফিক route করে না
এটি আরও গুরুতর, কারণ সবকিছু স্বাভাবিক মনে হয়। নাম resolve হয়, পেজ load হয়, এবং query cleartext অবস্থায় সেই local network-এর মধ্য দিয়ে যায়, যেটিকে আপনি trusted মনে করতে চাননি।
দুটি configuration এর কারণ। প্রথমটি হলো এমন client, যেখানে AllowedIPs = 0.0.0.0/0, ::/0 আছে কিন্তু কোনো DNS = line নেই। wg-quick নিজের routing table-এ default route install করে এবং suppress_prefixlength 0 দিয়ে একটি rule যোগ করে। এর ফলে ইচ্ছাকৃতভাবে আরও specific local route সক্রিয় থাকে, যাতে মেশিনটি নিজের printer-এ পৌঁছাতে পারে। Client DHCP-এর মাধ্যমে যে resolver শিখেছে, সাধারণত 192.168.1.1-এ থাকা router, সেটি ওই local route-গুলোর একটির সঙ্গে মিলে যায়। আপনার traffic tunnel-এর মধ্য দিয়ে যায়। কিন্তু local network-টি আপনি যে নামগুলোর query করেন, সেগুলোর সম্পূর্ণ তালিকা পেয়ে যায়।
দ্বিতীয়টি হলো split tunnel: AllowedIPs = 10.8.0.0/24 এবং DNS = 9.9.9.9। 9.9.9.9, AllowedIPs-এর মধ্যে নেই। তাই client-এর কাছে tunnel-এর মাধ্যমে সেখানে যাওয়ার কোনো route থাকে না। ফলে প্রথম ক্ষেত্রের মতো query local link দিয়ে বেরিয়ে যায়।
আসলে কোন resolver উত্তর দিচ্ছে, তা প্রমাণ করুন। whoami.akamai.net একটি public test name। এটি যে recursive resolver query করেছে, তার IP address দিয়ে উত্তর দেয়। তাই আপনি উত্তরটি আপনার server-এর public address-এর সঙ্গে তুলনা করতে পারবেন।
resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53resolvectl status প্রতিটি link-এর জন্য একটি করে block দেখায়। আপনার ethernet বা wireless link-এর block-এ যদি এখনও Current DNS Server: 192.168.1.1 দেখা যায়, অথচ wg0 block-এ কিছু না থাকে, তাহলে সেটিই leak। dig +short whoami.akamai.net-এর ফলাফলে server-এর address-এর বদলে আপনার home broadband address দেখা গেলে remote দিক থেকেও বিষয়টি নিশ্চিত হয়। বিতর্কের অবসান ঘটানোর মতো প্রমাণ হলো tcpdump line: সুস্থ output-এ port 53-এর প্রতিটি packet wg0-এর মধ্য দিয়ে যায়। leak থাকলে সেগুলো wlan0 বা enp3s0-এর মধ্য দিয়ে যায়।
সমাধানের দুটি অংশ আছে এবং দুটিই প্রয়োজন। DNS এমন একটি address-এ সেট করুন, যা tunnel-এর ভেতরে থাকে। এরপর নিশ্চিত করুন যে address-টি AllowedIPs-এর ভেতরেও আছে।
[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/1610.8.0.1, 10.8.0.0/24-এর ভেতরে আছে। তাই query encrypted হয়ে server-এ পাঠানো হয়। split tunnel-এ public resolver ব্যবহার করতেই হলে, এটিকে host route হিসেবে যোগ করুন: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32। এরপর packet-গুলো tunnel-এর মধ্য দিয়ে যায়। তবে আগের session-গুলো থেকে local network এখনও বুঝতে পারে যে আপনি ওই provider বেছে নিয়েছেন। নিজে চালানো resolver ব্যবহার করলে এই সমস্যা এড়ানো যায়।
Resolver assignment হলো হাতে তৈরি WireGuard এবং সমন্বিত mesh-এর মধ্যে দৃশ্যমান পার্থক্যগুলোর একটি। WireGuard-এর সঙ্গে Tailscale-এর তুলনা-এর tradeoff-এর অংশ এটি। self-hosted Headscale control server চালালে আপনার key material কোনো তৃতীয় পক্ষের কাছে না দিয়েই এই সমন্বয় পাওয়া যায়। শেষ কথাটিই যদি আপনার উদ্বেগের কারণ হয়, তাহলে মনে রাখুন, আপনার traffic encrypt করা key Tailscale কখনো ধরে রাখে না। বরং আরও গুরুত্বপূর্ণ প্রশ্ন হলো, breached coordination server বা চুরি হওয়া identity account আপনার network-এ কী অতিরিক্ত access দিতে পারে।
ব্যর্থতা তিন: Linux client-এ resolvconf এবং systemd-resolved-এর দ্বন্দ্ব
macOS, Windows, iOS এবং Android client-গুলো official app-এর মাধ্যমে DNS = প্রয়োগ করে এবং সাধারণত তেমন সমস্যা তৈরি করে না। Linux-এ এই setting একটি shell script প্রয়োগ করে, যেটিকে অনুমান করতে হয় আপনি একাধিক resolver manager-এর মধ্যে কোনটি ব্যবহার করছেন।
প্রথম ব্যর্থতাটি স্পষ্ট। sudo wg-quick up wg0 এই বার্তাসহ বন্ধ হয়ে যায়:
resolvconf: command not foundwg-quick, resolvconf চালু করার চেষ্টা করে, কিন্তু ওই binary ইনস্টল করা নেই। systemd-resolved-এর সঙ্গে কাজ করে এমন implementation ইনস্টল করুন। এরপর interface-টি আবার চালু করুন।
sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0দ্বিতীয় ব্যর্থতাটি নীরবে ঘটে। এটিই একটি পুরো সন্ধ্যা নষ্ট করতে পারে। Interface চালু হয়, resolvectl status wg0 সঠিকভাবে DNS Servers: 10.8.0.1 দেখায়, কিন্তু lookup এখনও পুরোনো resolver-এ যায়। systemd-resolved প্রতিটি link-এর জন্য আলাদা resolver list রাখে এবং প্রতিটি query-এর জন্য একটি link বেছে নেয়। কোনো একটি link-কে name-এর default route হিসেবে চিহ্নিত না করলে এটি wireless link-এর resolver ব্যবহার করতে থাকে, কারণ ওই link-এ একটি search domain আছে, কিন্তু আপনার link-এ নেই।
একই ধাপে resolver সেট করুন এবং default route দাবি করুন। %i interface-এর নামে প্রসারিত হয়, তাই এই block যেকোনো interface-এ অপরিবর্তিতভাবে কাজ করে।
[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %iএইভাবে PostUp ব্যবহার করলে DNS = line মুছে দিন। অন্যথায় দুটি mechanism resolver state লিখবে, কিন্তু পরে cleanup করবে শুধু একটি mechanism। ~. argument-টিই গুরুত্বপূর্ণ অংশ। এটি wg0-কে প্রতিটি name-এর routing domain হিসেবে চিহ্নিত করে। ফলে systemd-resolved প্রতিটি query-এর জন্য link বেছে না নিয়ে সব query সেখানে পাঠায়। এটি যাচাই করুন।
resolvectl status wg0স্বাভাবিক output-এ DNS Servers: 10.8.0.1 এবং Default Route: yes থাকে। Default Route যদি no পড়ে, তাহলে resolvectl domain অংশটি চালানো হয়নি এবং আপনি আবার link selection-এর অবস্থায় ফিরে গেছেন।
আরেকটি পরিস্থিতিও উল্লেখ করা দরকার। /etc/resolv.conf যদি /run/systemd/resolve/stub-resolv.conf-এর symlink না হয়ে একটি আসল file হয়, তাহলে অন্য কোনো component সাধারণত NetworkManager বা container runtime সেটির নিয়ন্ত্রণ করছে। অন্য কিছু debug করার আগে ls -l /etc/resolv.conf চালান। কারণ network পরিবর্তনের সময় ওই file পুনরায় লেখে এমন কোনো tool সবচেয়ে অসুবিধাজনক মুহূর্তে আপনার পরিবর্তন বাতিল করে দেবে।
টানেলের ওপর নিজের filtering resolver: উন্নত ধাপ
কোয়েরিগুলো নির্ভরযোগ্যভাবে টানেলের মধ্য দিয়ে চলাচল করলে দূর প্রান্তের resolver একটি নিয়ন্ত্রণকেন্দ্র হয়ে ওঠে। সেখানে AdGuard Home চালালে সংযুক্ত প্রতিটি ডিভাইসে blocklist filtering এবং query log পাওয়া যায়; client software বা প্রতিটি ডিভাইসের আলাদা configuration-এর প্রয়োজন হয় না। July 2026-এ যাচাই করা official install script-টি এক লাইনের।
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -vপ্রথমবার চালু হলে setup wizard port 3000-এ listening করে। ওই port প্রকাশ্যে খোলার পরিবর্তে টানেলের মাধ্যমে http://10.8.0.1:3000 ঠিকানায় এটি খুলুন। Wizard-এ DNS listen address এবং admin listen address—দুটিই 10.8.0.1 নির্ধারণ করুন। প্রথম ব্যর্থতার ক্ষেত্রে unbound যদি এখনও একই address ধরে রাখে, তাহলে আগে sudo systemctl disable --now unbound দিয়ে সেটি বন্ধ করুন। কারণ একই address-এ দুটি process UDP port 53-এ bind করতে পারে না, এবং দ্বিতীয় process listen udp 10.8.0.1:53: bind: address already in use সহ বন্ধ হয়ে যায়।
Client configuration-এ কোনো পরিবর্তন দরকার নেই, যদি সেগুলোতে আগে থেকেই DNS = 10.8.0.1 লেখা থাকে। এখন query log-এ প্রতিটি peer-এর প্রতিটি lookup দেখা যাবে। এটি বিনা খরচের সুবিধা নয়, বরং গোপনীয়তা সম্পর্কিত একটি বাস্তব সিদ্ধান্ত। আপনি trust আপনার Internet provider থেকে নিজের কাছে স্থানান্তর করছেন, এবং ওই server আপডেট রাখা আপনার দায়িত্ব। Internet-এ exposed কোনো server-এর জন্য আগে মৌলিক security ব্যবস্থা কার্যকর করতে হবে, এবং নতুন VPS-এর প্রথম দশ মিনিট অংশে সেগুলো দেখানো হয়েছে।
FAQ
আমার WireGuard tunnel সংযুক্ত হয়, কিন্তু নাম resolve হয় না কেন?
Tunnel প্যাকেট বহন করে, কিন্তু নাম resolve করে না। তাই tunnel সচল থাকা অবস্থায় lookup ব্যর্থ হলে বুঝতে হবে, আপনি যে resolver নির্দিষ্ট করেছেন সেটি উত্তর দিচ্ছে না। Client থেকে dig +short @10.8.0.1 example.com দিয়ে পরীক্ষা করুন। communication timed out reply-এর অর্থ হলো tunnel address-এ কোনো resolver listening করছে না; এর সাধারণ কারণ systemd-resolved stub শুধু 127.0.0.53-এ bind করা, অথবা server firewall wg0-এ আসা UDP port 53-এর traffic বাদ দিচ্ছে। আগে listener ঠিক করুন। এরপর শুধু wg0-এর জন্য port খুলুন।
WireGuard-এর মাধ্যমে আমার DNS leak করছে কি না কীভাবে পরীক্ষা করব?
Client-এ sudo tcpdump -ni any -c 10 port 53 চালান এবং browse করার সময় interface column দেখুন। প্রতিটি packet wg0-এ থাকা উচিত। যদি packet wireless বা ethernet interface-এ দেখা যায়, তাহলে query cleartext-এ বাইরে যাচ্ছে। dig +short whoami.akamai.net দিয়ে দ্বিতীয়ভাবে যাচাই করা যায়। এটি যে recursive resolver query করেছে তার public address দেখায়। তাই উত্তরটি যদি আপনার server-এর address না হয়, তাহলে leak নিশ্চিত।
Split tunnel ব্যবহার করলে কি DNS = line প্রয়োজন?
হ্যাঁ। Resolver address-টিও AllowedIPs-এর ভেতরে থাকতে হবে। নইলে client-এর কাছে সেখানে যাওয়ার কোনো route থাকবে না। AllowedIPs = 10.8.0.0/24 থাকলে 10.8.0.1-এর resolver অন্তর্ভুক্ত হয় এবং query encrypted থাকে। 9.9.9.9-এর মতো public resolver অন্তর্ভুক্ত নয়। তাই DNS line সঠিক দেখালেও query local link দিয়ে বাইরে চলে যায়।
resolvectl সঠিক server দেখায়, কিন্তু lookup অন্যত্র যায় কেন?
systemd-resolved প্রতিটি link-এর জন্য আলাদা resolver list রাখে এবং প্রতিটি query-এর জন্য একটি link নির্বাচন করে। তাই wg0-এ সঠিক entry থাকলেও অন্য কোনো link-এ names-এর জন্য default route থাকলে সেটি উপেক্ষিত হয়। Client-এর [Interface] block-এ PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. যোগ করুন এবং DNS = line সরিয়ে দিন। এরপর resolvectl status wg0-এর output-এ Default Route: yes দেখানোর কথা।
একাধিক client-এ সমস্যা হলে প্রথমে কোনটি ঠিক করা উচিত?
একটি Linux client আগে ঠিক করুন। কারণ mechanism দেখাতে পারে একমাত্র এটিই। resolvectl status এবং tcpdump জানায় কোন resolver উত্তর দিয়েছে এবং কোন interface দিয়ে packet গেছে। Phone ও desktop app একই DNS এবং AllowedIPs value ব্যবহার করে, কিন্তু এই অভ্যন্তরীণ তথ্য দেখায় না। তাই Linux client সঠিক হওয়ার পর আপনি ইতিমধ্যে যাচাই করা configuration-ই কপি করতে পারবেন।