সরাসরি পর্বে যান
পর্ব ৫৫ · ৬২-এর মধ্যে · মডিউল ৯

সমস্যা খোঁজা — tcpdump, Wireshark আর পদ্ধতিগত তদন্ত

Network Troubleshooting — tcpdump, Wireshark and a Systematic Method

Taught in Bangla, this lesson teaches systematic network troubleshooting: symptoms, reproduction and hypotheses, layer-by-layer methods such as bottom-up, top-down and half-split, an eight-step decision path for a site that will not load, how packet capture works, tcpdump options, filters and reading output line by line, Wireshark display filters, streams and statistics, eight recognisable problems in captures, counters and logs, and privacy and reporting.

এই পর্বে যা শিখবেন

  • একটি পদ্ধতি — লক্ষণ, পুনরুৎপাদন, অনুমান, এক পরিবর্তনে পরীক্ষা — আর কখন bottom-up, top-down বা half-split
  • “ওয়েবসাইট খুলছে না”-র আট ধাপের সিদ্ধান্ত-পথ, প্রতিটি ধাপের কমান্ড আর আগের কোন পর্বের সাথে যুক্ত
  • Capture কীভাবে কাজ করে (libpcap, BPF, promiscuous mode, mirror port), tcpdump-এর প্রধান option আর capture filter
  • tcpdump-এর আউটপুট লাইন ধরে পড়া, Wireshark-এর display filter, Follow TCP Stream আর Statistics
  • Capture দেখে চেনা আটটি সমস্যা, সহায়ক টুল (mtr, ss -ti, ethtool, nstat, curl -w), গোপনীয়তা আর ভালো রিপোর্ট লেখা

১ · অনুমানে নয়, পদ্ধতিতে — লক্ষণ, পুনরুৎপাদন আর অনুমান

“নেট নেই” — এই কথার পেছনে হতে পারে খোলা তার, DHCP, ভুল DNS, firewall-এর নতুন নিয়ম, মেয়াদোত্তীর্ণ certificate, বা সার্ভারের ত্রুটি। ভালো ইঞ্জিনিয়ার বেশি কমান্ড জানেন বলে দ্রুত নন; তিনি পদ্ধতি মানেন — প্রতিটি পরীক্ষা সম্ভাব্য কারণের তালিকা ছোট করে।

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

ধাপ ১ — লক্ষণটি ঠিকঠাক লেখা

“কাজ করছে না” কোনো লক্ষণ নয়। ডাক্তার যেমন রোগীর ইতিহাস নেন, তেমনি প্রথমে পাঁচটি প্রশ্নের উত্তর লিখুন:

  • কে? একজন ব্যবহারকারী, এক তলার সবাই, নাকি পুরো অফিস? শুধু Wi-Fi-তে, নাকি তারেও?
  • কী? ঠিক কোন বার্তা — “This site can't be reached”, “Connection timed out”, “502 Bad Gateway”, নাকি শুধু খুব ধীর? Screenshot আর ঘড়ির সময়সহ।
  • কোথায়? সব ওয়েবসাইট, নাকি একটি? একটি অ্যাপ, নাকি সব অ্যাপ? মোবাইল ডেটায় চলে কি?
  • কবে থেকে? আজ সকাল ১০টা থেকে, নাকি সব সময় বিকেলে? সব সময়, নাকি মাঝে মাঝে (intermittent)?
  • কী বদলেছে? নতুন router, OS update, firewall-এর নিয়ম, ISP বদল, certificate নবায়ন, DNS record — অভিজ্ঞতায় দেখা যায়, বেশিরভাগ হঠাৎ সমস্যার পেছনে সাম্প্রতিক কোনো পরিবর্তন থাকে।

ধাপ ২ — পুনরুৎপাদন, অনুমান, একবারে একটি পরিবর্তন

পুনরুৎপাদন (reproduce): নিজে সমস্যাটি ঘটাতে পারেন? মাঝে মাঝে ঘটলে মাপুন — “১০০টি অনুরোধে ৭টি ব্যর্থ” — আর আগে থেকে capture বা log চালু রাখুন। যে সমস্যা ঘটানো যায় না, তার সমাধানও যাচাই করা যায় না।

অনুমান আর পরীক্ষা: তথ্য দেখে একটি নির্দিষ্ট অনুমান বানান — “DNS resolver উত্তর দিচ্ছে না” — আর এমন একটি পরীক্ষা ভাবুন, যার ফল অনুমানটিকে ভুল প্রমাণ করতে পারে (যেমন অন্য resolver দিয়ে একই নাম খোঁজা)। তারপর একবারে একটিই জিনিস বদলান। একসাথে DNS বদলালেন, router restart করলেন আর VPN বন্ধ করলেন — সমস্যা গেল, কিন্তু কোনটিতে গেল কেউ জানে না; পরের বার আবার শূন্য থেকে শুরু।

লিখে রাখা: প্রতিটি কমান্ড, তার আউটপুট আর সময় একটি নোটে টুকে রাখুন। মাঝপথে অন্য কেউ দায়িত্ব নিলে, বা পরে মূল কারণ (root cause) খুঁজতে হলে এই নোটই ভরসা।

সহজ জিনিস আগে: তার লাগানো? Wi-Fi ঠিক নেটওয়ার্কে? IP ঠিকানা আছে? Gateway সাড়া দেয়? DNS কাজ করে? এক মিনিটের এই পাঁচ পরীক্ষায় বহু “জটিল” সমস্যা ধরা পড়ে।

সবচেয়ে প্রচলিত ভুল: প্রথম ব্যাখ্যাটিকেই সত্য ধরে (“নিশ্চয়ই ISP-র দোষ”) শুধু তার পক্ষের প্রমাণ খোঁজা। প্রতিটি অনুমান একটি প্রশ্ন; উত্তর দেবে পরীক্ষা।

২ · স্তর ধরে খোঁজা — bottom-up, top-down আর half-split

পর্ব ৩-এর স্তরের মডেল এখানে সবচেয়ে কাজের হাতিয়ার। প্রতিটি স্তর নিচের স্তরের ওপর নির্ভর করে: link না থাকলে IP অর্থহীন, IP না থাকলে DNS অর্থহীন, TCP সংযোগ না হলে TLS অর্থহীন। তাই একটি স্তর ঠিক প্রমাণ হলে তার নিচের সব স্তরও মোটামুটি ঠিক প্রমাণ হয় — কোনো স্তর থেকে উত্তর আসা মানে নিচের পথটুকু চালু।

পদ্ধতিকীভাবেকখন ভালোদুর্বলতা
Bottom-up (নিচ থেকে)physical → link → IP → transport → application, একে একেনতুন সংযোগ, কিছুই চলছে না, তার বা Wi-Fi নিয়ে সন্দেহ; নতুনদের জন্য নিরাপদসমস্যা ওপরের স্তরে হলে অনেক অকারণ পরীক্ষা
Top-down (ওপর থেকে)অ্যাপ্লিকেশন থেকে শুরু: ঠিক কোন error, কোন URL; তারপর নিচে নামাএকটি অ্যাপ বা সাইট চলে না, বাকি সব চলেনিচের স্তরের সমস্যা দেরিতে ধরা পড়ে
Half-split (মাঝখান থেকে ভাগ)মাঝের একটি পরীক্ষা (যেমন বাইরের IP-তে ping); সফল হলে ওপরের অর্ধেকে, ব্যর্থ হলে নিচের অর্ধেকে খোঁজাঅভিজ্ঞ হাতে দ্রুততম; লম্বা পথ বা অনেক উপাদানমাঝের পরীক্ষাটি ভুল ব্যাখ্যা করলে (যেমন ping আটকানো) ভুল অর্ধেকে চলে যাওয়া
ভালোর সাথে তুলনাযেখানে চলে আর যেখানে চলে না — দুটির পার্থক্য খোঁজা“মোবাইল ডেটায় চলে, অফিসে চলে না”ভালো উদাহরণ সব সময় পাওয়া যায় না

Half-split আসলে binary search (DSA কোর্সের পরিচিত কৌশল)। nটি সম্ভাব্য জায়গার মধ্যে একটি ত্রুটিপূর্ণ হলে, প্রতিটি পরীক্ষা সম্ভাবনা অর্ধেক করে, তাই সবচেয়ে খারাপ ক্ষেত্রে পরীক্ষা লাগে:

পরীক্ষার সংখ্যা = ⌈log₂ n⌉

যুক্তিটি সহজ: kটি হ্যাঁ/না পরীক্ষার ফল সর্বোচ্চ 2k রকম হতে পারে, আর nটি জায়গা আলাদা করতে হলে 2k ≥ n লাগবে — তাই k ≥ log₂ n; আর প্রতিবার ঠিক অর্ধেক করলে এই সংখ্যাতেই কাজ হয়। পরের অংশের আটটি ধাপে ভাগ করে গেলে ⌈log₂ ৮⌉ = ৩টি পরীক্ষা — যদি প্রতিটি ফল নির্ভরযোগ্য হয়। এই “যদি”-টিই আসল কথা: ICMP আটকানো থাকলে ping ব্যর্থ হয়েও পথ চালু থাকতে পারে (পর্ব ২০), তাই half-split-এ প্রতিটি “না”-কে একটি দ্বিতীয় পদ্ধতিতে (যেমন TCP সংযোগ) মিলিয়ে নিন।

৩ · “ওয়েবসাইট খুলছে না” — আট ধাপের সিদ্ধান্ত-পথ

সবচেয়ে প্রচলিত অভিযোগটি দিয়েই পদ্ধতিটি অনুশীলন করি। একজন ব্যবহারকারীর Linux ল্যাপটপ (Wi-Fi, ঠিকানা 192.168.0.105) থেকে https://shop.example.com খুলছে না। প্রতিটি ধাপে একটি প্রশ্ন, একটি কমান্ড, আর ফল দেখে সিদ্ধান্ত। প্রতিটি ধাপের বিস্তারিত আগের একটি পর্বে আছে — সংখ্যাগুলো টেবিলে।

ধাপপ্রশ্নLinuxWindowsব্যর্থ হলে সন্দেহপর্ব
১Link আছে?ip -br linkGet-NetAdapterতার, Wi-Fi সংযোগ, driver১৪, ১২
২IP ঠিকানা পেয়েছে?ip -4 addripconfigDHCP; 169.254.x.x মানে DHCP ব্যর্থ১৮
৩Gateway সাড়া দেয়?ip route, ping gatewayping gatewayLAN, ARP, router১৮, ২২
৪বাইরের IP পৌঁছায়?ping, mtrping, tracertISP, routing, NAT২০, ২২
৫নাম থেকে ঠিকানা হয়?getent hosts, digResolve-DnsNameDNS resolver, record৩৫
৬TCP 443 সংযোগ হয়?nc -vz, curl -vTest-NetConnection host -Port 443firewall, সার্ভার বন্ধ২৯, ৪৯
৭TLS handshake সফল?openssl s_clientব্রাউজারের certificate বার্তাcertificate, ঘড়ি, TLS version৪৮
৮HTTP উত্তর কী?curl -sIcurl.exe -I৪xx: অনুরোধ; ৫xx: সার্ভার বা proxy৩৬, ৩৮

এবার ধাপে ধাপে চলুন। নিচের আউটপুটগুলো একটি সাধারণ ল্যাপটপের উদাহরণ (চালানো নয়; ঠিকানাগুলো documentation-এর জন্য সংরক্ষিত)।

এই ধাপের পরীক্ষা
প্রশ্ন
ফল
যা বাদ গেল
আগের পর্ব
  1. Link. UP মানে interface চালু করা হয়েছে, আর LOWER_UP মানে নিচের স্তরে সত্যিই সংযোগ আছে — Wi-Fi-তে AP-র সাথে যুক্ত, তারে cable-এর অন্য প্রান্তে কেউ আছে। শুধু UP কিন্তু NO-CARRIER হলে তার খোলা বা Wi-Fi বিচ্ছিন্ন — ওপরের কোনো পরীক্ষার মানে নেই।
  2. IP ঠিকানা. 192.168.0.105/24 — DHCP ঠিকমতো ঠিকানা দিয়েছে। ঠিকানা না থাকলে, বা 169.254.x.x হলে (APIPA, link-local), যন্ত্রটি DHCP সার্ভারের উত্তর পায়নি — তখন পর্ব ১৮-এর DORA-র কোন ধাপে আটকাল, সেটিই প্রশ্ন।
  3. Gateway. Default route আছে, gateway 192.168.0.1, আর তিনটি ping-এরই উত্তর এসেছে প্রায় ২ ms-এ। অর্থাৎ LAN, ARP আর বাসার router চালু। মনে রাখুন: কিছু router ping-এর উত্তর দেয় না; তখন ip neigh-এ gateway-র MAC (REACHABLE) দেখতে পাওয়াও প্রমাণ।
  4. বাইরের IP — এখানেই half-split. নাম নয়, সরাসরি একটি পরিচিত public IP-তে ping. সফল, তাই ISP আর routing চালু — নিচের চারটি স্তর একসাথে প্রমাণিত। ব্যর্থ হলেও তাড়াহুড়ো নয়: অনেক নেটওয়ার্ক ICMP আটকায়, তাই TCP দিয়ে (ধাপ ৬) মিলিয়ে নিন। কোন hop-এ সমস্যা, তা দেখাতে পারে mtr (পর্ব ২০)।
  5. DNS. getent প্রোগ্রামগুলোর মতোই glibc-র পথে নাম খোঁজে, তাই এটি ব্রাউজারের অভিজ্ঞতার কাছাকাছি। ঠিকানা এসেছে। ব্যর্থ হলে পর্ব ৩৫-এর টেবিল দেখুন — NXDOMAIN (নাম নেই), SERVFAIL (resolver উত্তর জোগাড় করতে পারেনি) আর timeout (কেউ উত্তর দেয়নি) তিনটি আলাদা সমস্যা।
  6. TCP 443. nc -vz শুধু handshake করে দেখে, কোনো ডেটা পাঠায় না। সফল — পথের firewall port 443 খোলা রেখেছে আর সার্ভার শুনছে। “Connection refused” এলে port বন্ধ (RST এসেছে); কোনো উত্তর না এসে timeout হলে পথের কোনো firewall SYN নিঃশব্দে ফেলে দিচ্ছে।
  7. TLS. TLS 1.3 handshake সম্পূর্ণ, certificate-এর নাম মেলে, আর chain যাচাই OK. ব্যর্থ হলে বার্তাটিই পথ দেখায় — মেয়াদ শেষ, নাম মেলে না, ল্যাপটপের ঘড়ি ভুল, বা পুরোনো TLS version (পর্ব ৪৮-এর টেবিল)।
  8. HTTP — সমস্যা এখানে. উত্তর এসেছে, কিন্তু status code 502 (Bad Gateway), আর server: nginx. অর্থাৎ ব্যবহারকারীর দিক থেকে সব ঠিক; সার্ভারের সামনের reverse proxy চালু, কিন্তু তার পেছনের অ্যাপ্লিকেশন সার্ভার থেকে সে ঠিক উত্তর পায়নি। এখন আট লাইনের প্রমাণসহ সার্ভার-দলকে জানানো যায়: “আমাদের নেটওয়ার্ক, DNS, TCP আর TLS ঠিক; proxy ১০:১৫ থেকে 502 দিচ্ছে।”

এই পর্যবেক্ষণগুলো একটি ছোট “সিদ্ধান্ত-যন্ত্রে” বসানো যায়: ক্রমানুসারে পরীক্ষা, প্রথম আসল ব্যর্থতায় থামা — তবে ওপরের স্তরের কোনো পরীক্ষা সফল হলে ping-এর ব্যর্থতা আসল নয়। নিচের কোড ছয়টি ঘটনায় সম্ভাব্য ত্রুটিপূর্ণ স্তর আর পরের কমান্ড ছাপে। “চালান” চাপুন, তারপর cases-এ নিজের পর্যবেক্ষণ যোগ করে দেখুন:

// "Website doesn't open": walk the checks bottom-up and stop at the first real failure.
const checks = [   // [observation, fault layer if it fails, next command, lesson no.]
  ["link",     "physical/link (cable, Wi-Fi)",        "ip -br link ; iw dev wlan0 link",                "14"],
  ["ip",       "IP config (DHCP)",                    "ip -4 addr ; journalctl -u NetworkManager",      "18"],
  ["gw_ping",  "local LAN / gateway",                 "ip route ; ip neigh show",                       "18, 22"],
  ["wan_ping", "ISP / routing beyond the gateway",    "mtr -rwn -c 50 <public-IP>",                      "20, 22"],
  ["dns_ok",   "DNS",                                 "dig example.com ; resolvectl status",            "35"],
  ["tcp_443",  "transport: port 443 blocked/closed",  "curl -v --connect-timeout 5 https://example.com", "29, 49"],
  ["tls_ok",   "TLS (certificate, clock, version)",   "openssl s_client -connect example.com:443 -servername example.com", "48"],
];
function diagnose(o) {
  for (const [i, [key, layer, cmd, n]] of checks.entries()) {
    if (o[key] !== false) continue;
    const laterOk = checks.slice(i + 1).some(([k]) => o[k] === true);
    if (key.endsWith("ping") && laterOk) {                 // ping failed, but higher layers work
      console.log(`     note: ${key} failed but later checks pass -> ICMP is filtered, not the fault`);
      continue;
    }
    return `${layer}\n     next: ${cmd}   (lesson ${n})`;
  }
  if (o.http_status >= 500) return `server or proxy side (HTTP ${o.http_status})\n     next: curl -sv -o /dev/null https://example.com ; read proxy/server logs   (lesson 36, 38)`;
  if (o.http_status >= 400) return `request side (HTTP ${o.http_status}: URL, login, permission)\n     next: curl -v, check URL and cookies   (lesson 36)`;
  return "network path is fine -> look at the browser (cache, extension, proxy setting)";
}
const T = true, F = false;
const cases = {   // observations in check order: link, ip, gw_ping, wan_ping, dns_ok, tcp_443, tls_ok
  "A: Wi-Fi connected, no IP":   { link: T, ip: F },
  "B: everything but names":     { link: T, ip: T, gw_ping: T, wan_ping: T, dns_ok: F },
  "C: ping blocked, site 502":   { link: T, ip: T, gw_ping: T, wan_ping: F, dns_ok: T, tcp_443: T, tls_ok: T, http_status: 502 },
  "D: TCP ok, TLS fails":        { link: T, ip: T, gw_ping: T, wan_ping: T, dns_ok: T, tcp_443: T, tls_ok: F },
  "E: gateway and internet silent": { link: T, ip: T, gw_ping: F, wan_ping: F, dns_ok: F },
  "F: all good, HTTP 200":       { link: T, ip: T, gw_ping: T, wan_ping: T, dns_ok: T, tcp_443: T, tls_ok: T, http_status: 200 },
};
for (const [name, obs] of Object.entries(cases)) { console.log(name); console.log("  -> " + diagnose(obs)); }

আসল রানের আউটপুট:

A: Wi-Fi connected, no IP
  -> IP config (DHCP)
     next: ip -4 addr ; journalctl -u NetworkManager   (lesson 18)
B: everything but names
  -> DNS
     next: dig example.com ; resolvectl status   (lesson 35)
C: ping blocked, site 502
     note: wan_ping failed but later checks pass -> ICMP is filtered, not the fault
  -> server or proxy side (HTTP 502)
     next: curl -sv -o /dev/null https://example.com ; read proxy/server logs   (lesson 36, 38)
D: TCP ok, TLS fails
  -> TLS (certificate, clock, version)
     next: openssl s_client -connect example.com:443 -servername example.com   (lesson 48)
E: gateway and internet silent
  -> local LAN / gateway
     next: ip route ; ip neigh show   (lesson 18, 22)
F: all good, HTTP 200
  -> network path is fine -> look at the browser (cache, extension, proxy setting)

A আর E — নিচের স্তরে থামা: A-তে ঠিকানা নেই, তাই পরের প্রশ্ন DHCP-র। E-তে gateway, বাইরের IP আর DNS — তিনটিই ব্যর্থ, ওপরের কিছুই সফল নয়; তাই gateway-র ping-ই আসল ব্যর্থতা, আর পরের কমান্ড ip route আর ip neigh.

B আর D — মাঝের স্তর: B-তে ping সব চলে, শুধু নাম খোঁজা ব্যর্থ — তাই DNS. D-তে TCP হয়, TLS হয় না — তাই certificate, ঘড়ি বা version.

C — ping-এর ফাঁদ: বাইরের IP-তে ping ব্যর্থ, কিন্তু DNS, TCP 443 আর TLS সফল। যন্ত্রটি তাই note: wan_ping failed but later checks pass -> ICMP is filtered, not the fault লিখে এগিয়ে গেছে, আর আসল কারণ পেয়েছে HTTP 502-এ — সার্ভার বা proxy-র দিক। শুধু ping দেখে “ইন্টারনেট নেই” বললে এখানে ভুল দলকে ডাকা হতো। F-এ সব পরীক্ষা সফল; তখন নেটওয়ার্ক নয়, ব্রাউজারের দিকটা (cache, extension, proxy সেটিং) দেখার পালা।

৪ · Packet capture কীভাবে কাজ করে — tcpdump-এর option আর filter

কমান্ডগুলো বলে “কী হলো”; packet capture দেখায় “ঠিক কীভাবে হলো”। পর্ব ৬-এ tcpdump আর Wireshark-এর প্রথম পরিচয় পেয়েছেন। এবার ভেতরটা দেখি।

Capture-এর যন্ত্রপাতি

  • libpcap: tcpdump, Wireshark আর আরও বহু টুল packet ধরতে একই লাইব্রেরি ব্যবহার করে। Linux-এ এটি kernel-এর একটি packet socket খোলে, যা interface দিয়ে আসা-যাওয়া প্রতিটি packet-এর একটি কপি পায় — আসল packet নিজের পথে চলতেই থাকে। Windows-এ একই কাজ করে Npcap driver, macOS-এ /dev/bpf* যন্ত্র।
  • BPF filter: সব packet kernel থেকে প্রোগ্রামে কপি করা ব্যয়বহুল। তাই আপনার লেখা filter (যেমন tcp port 443) ছোট একটি bytecode প্রোগ্রামে রূপান্তরিত হয়ে kernel-এর ভেতরে বসে, আর না-মেলা packet সেখানেই বাদ পড়ে। tcpdump -d 'tcp port 443' সেই bytecode ছাপে।
  • Promiscuous mode: সাধারণত network card শুধু নিজের MAC ঠিকানার, broadcast আর বেছে নেওয়া multicast frame ওপরে পাঠায়। Promiscuous mode-এ সে সব frame পাঠায়। কিন্তু আজকের switch-চালিত নেটওয়ার্কে (পর্ব ১২) switch অন্যের frame আপনার port-এ পাঠায়ই না — তাই promiscuous mode চালু করেও সাধারণত শুধু নিজের traffic আর broadcast দেখবেন।
  • অন্যের traffic দেখার বৈধ উপায়: নেটওয়ার্কের দায়িত্বে থাকলে managed switch-এ একটি port-এর traffic আরেকটি port-এ কপি করা — port mirroring (Cisco-র ভাষায় SPAN), অথবা তারের মাঝে বসানো হার্ডওয়্যার TAP. দুটিই অনুমতি নিয়ে বসানো হয়।

কোথায় capture করবেন — host-এ, নাকি নেটওয়ার্কে

একই সংযোগের capture দুই প্রান্তে আলাদা গল্প বলে; দুটি মেলালে বোঝা যায় packet পথে হারাচ্ছে কি না। আরেকটি গুরুত্বপূর্ণ সূক্ষ্মতা: Linux-এ tcpdump আগত packet দেখে firewall-এর আগেই। তাই “tcpdump-এ SYN দেখা যাচ্ছে, কিন্তু অ্যাপ কিছু পাচ্ছে না, SYN-ACK-ও যাচ্ছে না” — এটি প্রায় নিশ্চিতভাবে host-এর নিজের firewall (netfilter, পর্ব ৪৯)। উল্টো দিকে, বাইরে যাওয়ার packet firewall-এ আটকালে tcpdump-এ পৌঁছায়ই না।

Capture-এ root লাগে, বা Linux-এ CAP_NET_RAW আর CAP_NET_ADMIN capability (অনেক distribution Wireshark-এর dumpcap-কে একটি বিশেষ group-এর জন্য এই অনুমতি দেয়)। কারণ পরিষ্কার: যে packet দেখতে পারে, সে অন্যের পাসওয়ার্ডও দেখতে পারে।

tcpdump-এর প্রধান option

Optionমানেকেন দরকার
-i eth0, -i anyকোন interface; any = সবগুলো (Linux)ভুল interface-এ capture নতুনদের সবচেয়ে প্রচলিত ভুল; tcpdump -D তালিকা দেখায়
-n / -nn-n: IP-কে নাম বানাবে না; -nn: port-কেও নাম (https) বানাবে নানাম খুঁজতে tcpdump নিজেই DNS প্রশ্ন পাঠায় — ধীর হয় আর capture-এ নিজের traffic ঢোকে
-v, -vvআরও বিস্তারিত: TTL, IP id, মোট দৈর্ঘ্য, checksumTTL বা fragment-এর সমস্যায়
-c 100১০০টি packet ধরে থামবেব্যস্ত সার্ভারে টার্মিনাল ভেসে যাওয়া থেকে রক্ষা
-w file.pcap / -r file.pcapফাইলে লেখা / ফাইল থেকে পড়াসার্ভারে ধরুন, নিজের ল্যাপটপে Wireshark-এ খুলুন
-s 128snaplen: প্রতিটি packet-এর প্রথম কত বাইট রাখবে (আধুনিক ডিফল্ট ২৬২১৪৪ — অর্থাৎ পুরোটা)শুধু header দরকার হলে ছোট snaplen ফাইল ছোট রাখে আর কম ব্যক্তিগত তথ্য ধরে

Capture filter — BPF-এর ভাষা

নিচের উদাহরণগুলো একটি সাধারণ Linux যন্ত্রের, নিজের যন্ত্রে root হিসেবে (এই পাতার রানারে tcpdump নেই, আর capture-এর অনুমতিও নেই)। Filter সব সময় একক উদ্ধৃতিচিহ্নে রাখুন, যাতে shell কোনো চিহ্ন (&, !, [ ]) নিজে ব্যাখ্যা না করে:

sudo tcpdump -i eth0 -nn 'host 192.0.2.10'                 # ওই ঠিকানা থেকে বা ওই ঠিকানায়
sudo tcpdump -i eth0 -nn 'net 198.51.100.0/24 and port 53'  # একটি subnet-এর DNS
sudo tcpdump -i eth0 -nn 'tcp port 443 and not port 22'     # নিজের SSH সেশন বাদ
sudo tcpdump -i any  -nn 'tcp[tcpflags] & tcp-syn != 0'     # শুধু SYN আর SYN-ACK
sudo tcpdump -i any  -nn 'tcp[tcpflags] & (tcp-rst|tcp-fin) != 0'  # সংযোগ শেষের packet
sudo tcpdump -i eth0 -nn 'icmp'                             # ping, unreachable, frag-needed
sudo tcpdump -i eth0 -nn -s 128 -c 2000 -w /tmp/web.pcap 'host 203.0.113.80 and tcp port 443'

tcp[tcpflags] মানে TCP header-এর flag-বাইট (পর্ব ২৯-এর header-এর ১৩ নম্বর বাইট); & tcp-syn != 0 মানে “SYN বিটটি ১”। খেয়াল করুন, SYN-ACK-এও SYN বিট ১, তাই দুটোই ধরা পড়ে — নতুন সংযোগের চেষ্টা গুনতে এটি খুব কাজের। আর SSH দিয়ে দূরের সার্ভারে capture করলে not port 22 না দিলে tcpdump নিজের আউটপুটের SSH packet ধরে, সেটি আবার ছাপে, আবার ধরে — অন্তহীন চক্র।

একটি সূক্ষ্ম নিয়ম, যা প্রায় সবাই ভুল করেন: pcap-filter-এর ভাষায় not সবচেয়ে আগে প্রয়োগ হয়, কিন্তু and আর or-এর অগ্রাধিকার সমান, আর এরা বাম থেকে ডানে চলে — C বা Python-এর মতো and আগে নয়। নিচের ছোট evaluator ঠিক এই নিয়মে ছয়টি packet-এ পাঁচটি filter চালায়:

// A tiny pcap-filter evaluator. Like real BPF syntax: "not" binds tightest,
// "and"/"or" have EQUAL precedence and are applied left to right.
const pkts = [
  { n: 1, proto: "tcp",  src: "192.0.2.10",   dst: "198.51.100.20", sport: 50412, dport: 443, flags: "S" },
  { n: 2, proto: "tcp",  src: "198.51.100.20", dst: "192.0.2.10",  sport: 443, dport: 50412, flags: "SA" },
  { n: 3, proto: "udp",  src: "192.0.2.10",   dst: "192.0.2.53",   sport: 40001, dport: 53 },
  { n: 4, proto: "icmp", src: "192.0.2.1",    dst: "192.0.2.10" },
  { n: 5, proto: "tcp",  src: "192.0.2.77",   dst: "192.0.2.10",   sport: 51000, dport: 22, flags: "PA" },
  { n: 6, proto: "tcp",  src: "198.51.100.20", dst: "192.0.2.10",  sport: 443, dport: 50412, flags: "R" },
];
const inNet = (ip, cidr) => { const [base, len] = cidr.split("/"), size = 2 ** (32 - len),
  v = a => a.split(".").reduce((x, o) => x * 256 + +o, 0); return Math.floor(v(ip) / size) === Math.floor(v(base) / size); };
function prim(t, p) {                     // t = tokens of one primitive, e.g. ["src","port","53"]
  if (["tcp", "udp", "icmp"].includes(t[0]) && t.length > 1) return p.proto === t.shift() && prim(t, p);
  const dir = t[0] === "src" || t[0] === "dst" ? t.shift() : null, [kind, arg] = t;
  const pick = (a, b) => dir === "src" ? [a] : dir === "dst" ? [b] : [a, b];
  if (kind === "host") return pick(p.src, p.dst).includes(arg);
  if (kind === "net")  return pick(p.src, p.dst).some(ip => inNet(ip, arg));
  if (kind === "port") return pick(p.sport, p.dport).includes(+arg);
  if (kind === "SYN")  return p.proto === "tcp" && p.flags.includes("S");
  return p.proto === kind;                // tcp, udp, icmp
}
function match(expr, p) {
  const toks = expr.replace("tcp[tcpflags] & tcp-syn != 0", "SYN").split(/\s+/);
  let result = null, op = null, neg = false, cur = [];
  const flush = () => { if (!cur.length) return; let v = prim(cur, p) !== neg; cur = []; neg = false;
    result = result === null ? v : op === "and" ? result && v : result || v; };
  for (const w of toks) {
    if (w === "and" || w === "or") { flush(); op = w; } else if (w === "not") neg = true; else cur.push(w);
  }
  flush(); return result;
}
for (const f of ["host 198.51.100.20", "udp port 53 or icmp", "tcp[tcpflags] & tcp-syn != 0",
                 "net 192.0.2.0/24 and not port 22", "src host 192.0.2.10 or icmp and port 443"])
  console.log(f.padEnd(34), "->", pkts.filter(p => match(f, p)).map(p => "#" + p.n).join(" ") || "(none)");

আসল রানের আউটপুট:

host 198.51.100.20                 -> #1 #2 #6
udp port 53 or icmp                -> #3 #4
tcp[tcpflags] & tcp-syn != 0       -> #1 #2
net 192.0.2.0/24 and not port 22   -> #1 #2 #3 #4 #6
src host 192.0.2.10 or icmp and port 443 -> #1

প্রথম চারটি: host উৎস বা গন্তব্য — যেকোনোটি মিললেই হয়, তাই #১, #২, #৬. udp port 53 আসলে “udp এবং port 53” — #৩; সাথে icmp — #৪. SYN-filter ধরেছে #১ (SYN) আর #২ (SYN-ACK). net 192.0.2.0/24 and not port 22 ধরেছে #৪-ও: ICMP-এর port নেই, তাই “port 22 নয়” তার জন্য সত্য — বাস্তব tcpdump-ও তাই করে।

শেষটি — অগ্রাধিকারের ফাঁদ: src host 192.0.2.10 or icmp and port 443 বাম থেকে ডানে পড়া হয়েছে (src host 192.0.2.10 or icmp) and port 443 হিসেবে, তাই শুধু #১. C-র নিয়মে পড়লে (and আগে) #৩-ও মিলত, কারণ সেটির উৎস 192.0.2.10. সমাধান সহজ: মিশ্র filter-এ সব সময় বন্ধনী দিন — 'src host 192.0.2.10 or (icmp and port 443)'.

৫ · tcpdump-এর আউটপুট লাইন ধরে পড়া

প্রতিটি TCP লাইনের গঠন একই: সময় · IP · উৎস.port > গন্তব্য.port · Flags · seq (এই packet-এর ডেটা কোন বাইট থেকে কোন বাইট) · ack (পরের কোন বাইট আশা করছি) · win (আর কত জায়গা আছে) · options · length (ডেটার বাইট)। Flag-এর চিহ্নগুলো: S = SYN, F = FIN, P = PUSH, R = RST, আর . = ACK. তাই [S.] মানে SYN + ACK, [P.] মানে ডেটাসহ ACK.

নিচে একটি client (192.0.2.10) একটি ওয়েব সার্ভার (198.51.100.20, port 80) থেকে একটি ছোট পাতা আনছে — সংযোগ, অনুরোধ, উত্তর আর বন্ধ। Capture client-এর (sudo tcpdump -i eth0 -nn 'host 198.51.100.20 and port 80', উদাহরণ)। সাধারণ HTTP ব্যবহার করা হয়েছে যাতে অনুরোধের লেখা দেখা যায়; HTTPS-এ একই TCP-র ছবি, শুধু ডেটা এনক্রিপ্ট করা।

এই ধাপের লাইন
flag
seq / ack
window
client-এর অবস্থা
  1. SYN. Client 192.0.2.10-এর ephemeral port ৫১৫১৪ থেকে সার্ভারের ৮০-তে [S]. seq 1546821000 হলো client-এর এলোমেলোভাবে বাছা শুরুর নম্বর (ISN). Options-এ client জানাচ্ছে: আমার MSS ১৪৬০, আমি SACK বুঝি, timestamp (TS val) দিচ্ছি, আর window-কে ২⁷ = ১২৮ দিয়ে গুণ করে পড়বেন (wscale 7). length 0 — SYN-এ ডেটা নেই।
  2. SYN-ACK. সার্ভারের [S.] এলো ১০:১৫:০২.১৩০৪১২-এ — SYN-এর ৩০.৪ ms পরে; এটিই প্রথম RTT-এর মাপ। সার্ভারের নিজের ISN 3870001234, আর ack 1546821001 = client-এর ISN + ১ — SYN নিজে একটি sequence নম্বর “খরচ” করে। ecr 3011 client-এর timestamp ফেরত দিচ্ছে।
  3. ACK — সংযোগ চালু. Client-এর [.], আর হঠাৎ ack 1! tcpdump দ্বিতীয় packet থেকে seq আর ack আপেক্ষিক দেখায় (ISN বাদ দিয়ে), যাতে পড়া সহজ হয়; আসল সংখ্যা দেখতে -S. win 502 এখন scale করা: ৫০২ × ১২৮ = ৬৪,২৫৬ বাইট। SYN-এর win 64240 কিন্তু scale ছাড়া — handshake-এর packet-এ window scale প্রয়োগ হয় না।
  4. অনুরোধ. [P.] seq 1:79, length 78 — ডেটার বাইট ১ থেকে ৭৮ (শেষ সংখ্যা ৭৯ “পরের বাইট”, অন্তর্ভুক্ত নয়)। tcpdump port 80 দেখে প্রথম লাইন দেখিয়েছে: GET / HTTP/1.1. প্রায় ৩০ ms পরে সার্ভারের ack 79 — “৭৮ পর্যন্ত পেয়েছি, ৭৯ থেকে পাঠান”।
  5. উত্তর. সার্ভার পাঠাল ৬১২ বাইট (seq 1:613), প্রথম লাইন HTTP/1.1 200 OK. Client ৪৮ µs পরেই ack 613 দিল। লক্ষ করুন, client-এর window ৫০২ থেকে ৫০১ হয়েছে — ৬১২ বাইট এখনো অ্যাপ পড়েনি, buffer-এ জায়গা সামান্য কম।
  6. বন্ধ. Client-এর [F.] seq 79 — “আমার আর কিছু পাঠানোর নেই”; সার্ভারের [F.] seq 613, ack 80 — FIN-ও SYN-এর মতো একটি sequence নম্বর খায়, তাই ৭৯ নয়, ৮০; শেষে client-এর ack 614. সার্ভার এখানে নিজের FIN-এর সাথেই ACK দিয়েছে, তাই চারটির বদলে তিনটি packet. সংযোগ যে আগে FIN পাঠায়, সেই client যায় TIME-WAIT-এ (পর্ব ২৯)। [R] দেখলে বুঝবেন সংযোগ ভদ্রভাবে নয়, হঠাৎ কাটা হয়েছে।

৬ · Wireshark — display filter, stream আর পরিসংখ্যান

tcpdump সার্ভারে ধরার জন্য, Wireshark বিশ্লেষণের জন্য — প্রতিটি packet স্তর ধরে খুলে দেখায়, আর TCP-র আচরণ নিজেই চিহ্নিত করে। সাধারণ ধারা: সার্ভারে tcpdump -w, ফাইল নিজের যন্ত্রে এনে Wireshark-এ খোলা।

একটু ইতিহাস: Gerald Combs ১৯৯৮ সালে Ethereal নামে প্রোগ্রামটি প্রকাশ করেন। ২০০৬ সালে চাকরি বদলের সময় “Ethereal” নামের trademark আগের প্রতিষ্ঠানের কাছে থেকে যায়, তাই প্রকল্পটি নতুন নামে চলতে থাকে — Wireshark. এর command-line রূপ tshark, আর ডিফল্ট ফাইল-format pcapng.

দুই রকম filter — গুলিয়ে ফেলবেন না

Capture filter

BPF ভাষা, tcpdump-এর মতো। ধরার আগে ঠিক করে কোন packet আদৌ রাখা হবে — যা বাদ গেল, তা আর ফেরত আনা যায় না।

tcp port 443 and host 192.0.2.10

Display filter

Wireshark-এর নিজের ভাষা, protocol-এর ঘরের নাম দিয়ে। ধরার পরে শুধু দেখানো বাছাই করে — যতবার খুশি বদলানো যায়।

tcp.port == 443 && ip.addr == 192.0.2.10

সমস্যা খোঁজায় সবচেয়ে কাজের কয়েকটি display filter (উদাহরণ; প্রতিটি Wireshark-এর filter বারে লিখে Enter):

tcp.analysis.retransmission          # Wireshark যেগুলোকে retransmission চিনেছে
tcp.analysis.duplicate_ack           # dup ACK — প্রাপক একটি ফাঁক দেখছে
tcp.analysis.zero_window             # প্রাপকের buffer ভরা
tcp.flags.reset == 1                 # RST — সংযোগ হঠাৎ কাটা
dns.flags.rcode != 0                 # ত্রুটিসহ DNS উত্তর (3 = NXDOMAIN, 2 = SERVFAIL)
http.response.code >= 400            # HTTP-র ত্রুটির উত্তর
tls.handshake.type == 1              # TLS ClientHello
tls.alert_message                    # TLS alert (যেমন handshake_failure)
icmp.type == 3 && icmp.code == 4     # Fragmentation Needed — PMTUD-র বার্তা
tcp.stream eq 7                      # শুধু ৭ নম্বর TCP সংযোগ

তিনটি সবচেয়ে কাজের মেনু

  • Follow → TCP Stream: পুরো সংযোগের ডেটা কথোপকথনের মতো দেখায় — client এক রঙে, সার্ভার আরেক রঙে। সাধারণ HTTP বা SMTP-তে অসাধারণ; HTTPS-এ শুধু এনক্রিপ্ট করা বাইট।
  • Statistics → Conversations আর IO Graph: Conversations দেখায় কোন দুই ঠিকানার মধ্যে কত বাইট গেছে — “কে bandwidth খাচ্ছে” এক নজরে। IO Graph সময়ের সাথে প্রতি সেকেন্ডের packet বা বাইট আঁকে — হঠাৎ থেমে যাওয়া চোখে পড়ে; retransmission-এর জন্য আলাদা রেখাও আঁকা যায়।
  • Analyze → Expert Information: Wireshark-এর নিজের সতর্কবার্তার তালিকা — “Previous segment not captured”, “Dup ACK”, “Fast retransmission”, “Zero window” — শুরু করার ভালো জায়গা, কিন্তু রায় নয়: capture শুরুর আগের packet না থাকলেও “not captured” আসে।

৭ · Capture দেখে চেনা আটটি পরিচিত সমস্যা

অভিজ্ঞ ইঞ্জিনিয়ার capture-এ কয়েকটি “ছাপ” চেনেন — ডাক্তার যেমন এক্স-রে-তে ভাঙা হাড় চেনেন:

Capture-এ যা দেখবেনসম্ভাব্য কারণপরের পদক্ষেপ
SYN, তারপর একই SYN আবার — ১, ৩, ৭ সেকেন্ডে (Linux), কোনো উত্তর নেইপথের firewall নিঃশব্দে ফেলে দিচ্ছে, host বন্ধ, বা ফেরার route নেইসার্ভারে capture — SYN পৌঁছায়? পৌঁছালে host firewall; না পৌঁছালে পথ (পর্ব ৪৯)
SYN-এর পরেই [R.], এক RTT-র মধ্যেসার্ভার জীবিত, কিন্তু ওই port-এ কেউ শুনছে না — “Connection refused” (বা firewall-এর reject নিয়ম)সার্ভারে ss -tlnp; সার্ভিস চালু? ঠিক ঠিকানায় (0.0.0.0 না 127.0.0.1) শুনছে?
Retransmission, আগে তিনটি dup ACKপথে packet loss — জ্যাম, খারাপ Wi-Fi, ত্রুটিপূর্ণ তারmtr, ip -s link-এ error, ss -ti-এ retrans (পর্ব ৩০)
win 0 প্রাপকের দিক থেকে, প্রেরকের window probeZero window — নেটওয়ার্ক নয়, প্রাপক অ্যাপ ধীরে পড়ছেপ্রাপকের CPU, disk, অ্যাপের log (পর্ব ৩১)
Handshake আর ছোট packet চলে, বড় (১৪০০+ বাইট) packet বারবার retransmit, কোনো ICMP নেইPMTUD black hole — পথে ছোট MTU, “Fragmentation Needed” আটকানোping -M do -s, tracepath (পর্ব ২০); নিচের স্টেপার
DNS query যায়, উত্তর আসে না, ৫ সেকেন্ড পরে আবারResolver পৌঁছায় না বা UDP 53 আটকানো — timeoutঅন্য resolver দিয়ে dig @…; firewall
DNS উত্তর আসে, কিন্তু rcode NXDOMAINনাম সত্যিই নেই — বানান, মেয়াদ, record যোগ হয়নি; নেটওয়ার্ক ঠিকdig +trace (পর্ব ৩৫)
ClientHello-র পরেই সার্ভারের TLS alert (handshake_failure, protocol_version)TLS version বা cipher-এ মিল নেই — পুরোনো client বা কড়া সার্ভারopenssl s_client -tls1_2 / -tls1_3 (পর্ব ৪৮)
সব TCP/TLS ঠিক, কিন্তু HTTP 502/504, server: nginx বা CDN-এর নামProxy চালু, পেছনের সার্ভার উত্তর দিচ্ছে না বা দেরি করছেProxy-র error log (অংশ ৮); 502 = সংযোগ ব্যর্থ, 504 = সময় পার (পর্ব ৩৬)

প্রথম সারির সময়গুলো কোথা থেকে? Linux-এ SYN-এর প্রথম timeout ১ সেকেন্ড, আর প্রতিবার দ্বিগুণ হয় (পর্ব ৩০-এর exponential backoff) — তাই পুনরায় পাঠানো হয় ১, ৩, ৭, ১৫, ৩১, ৬৩ সেকেন্ডে, আর ডিফল্ট ৬টি চেষ্টার পরে প্রায় ১২৭ সেকেন্ডে connect() হাল ছাড়ে। Capture-এ এই ছন্দ দেখলেই বুঝবেন: উত্তর আসছে না, প্রত্যাখ্যানও নয়।

একটি capture নিজে বিশ্লেষণ করা

Wireshark-এর বিশ্লেষণের মূল যুক্তি সরল: প্রতিটি দিকে পরের কোন বাইট আশা করছেন মনে রাখুন; পুরোনো বাইট আবার এলে retransmission, আরও পরের বাইট এলে ফাঁক; একই ack একই window-সহ বারবার এলে dup ACK; win 0 হলে zero window. নিচের কোড একটি হাতে লেখা, বাস্তবসম্মত tcpdump transcript পড়ে — client-এ নেওয়া capture (বাস্তবে timestamp আর SACK option-ও থাকত; সংক্ষেপের জন্য বাদ):

// Annotate a hand-written tcpdump -nn transcript: S = server 198.51.100.20.443, C = client 192.0.2.10.50412
const raw = `10:20:01.000000 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], seq 1:1449, ack 1, win 509, length 1448
10:20:01.000040 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 1449, win 501, length 0
10:20:01.000300 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], seq 2897:4345, ack 1, win 509, length 1448
10:20:01.000340 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 1449, win 501, length 0
10:20:01.000600 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], seq 4345:5793, ack 1, win 509, length 1448
10:20:01.000640 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 1449, win 501, length 0
10:20:01.000900 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], seq 5793:7241, ack 1, win 509, length 1448
10:20:01.000940 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 1449, win 501, length 0
10:20:01.031000 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], seq 1449:2897, ack 1, win 509, length 1448
10:20:01.031040 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 7241, win 120, length 0
10:20:01.061000 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [P.], seq 7241:8689, ack 1, win 509, length 1448
10:20:01.061040 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 8689, win 0, length 0
10:20:01.291000 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [.], ack 1, win 509, length 0
10:20:01.291040 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 8689, win 0, length 0
10:20:01.700000 IP 192.0.2.10.50412 > 198.51.100.20.443: Flags [.], ack 8689, win 501, length 0
10:20:01.730000 IP 198.51.100.20.443 > 192.0.2.10.50412: Flags [P.], seq 8689:10137, ack 1, win 509, length 1448`;
const re = /^(\S+) IP (\S+) > (\S+): Flags \[([^\]]+)\],(?: seq (\d+):(\d+),)? ack (\d+), win (\d+), length (\d+)/;
const next = {}, last = {}; let dups = 0;
for (const line of raw.split("\n")) {
  const [, t, src, , flags, s, e, ack, win, len] = line.match(re);
  const who = src.endsWith(".443") ? "S" : "C", L = +len, W = +win; let note = "";
  if (L > 0) {                                        // a data segment
    const exp = next[who] ?? +s;
    note = +e <= exp ? `RETRANSMISSION of ${s}:${e}` + (dups >= 3 ? " (fast retransmit after 3 dup ACKs)" : "")
         : +s > exp ? `GAP: bytes ${exp}:${s} not seen yet (lost or reordered)` : "new data";
    next[who] = Math.max(exp, +e);
  } else if (who === "S" && last.C && last.C.win === 0) note = "WINDOW PROBE: are you still at win 0?";
  else if (W === 0) note = "ZERO WINDOW: receiver buffer full, sender must stop";
  else if (last[who] && last[who].win === 0) note = `WINDOW UPDATE: win ${W}, sender may continue`;
  else if (last[who] && last[who].ack === +ack && last[who].win === W && flags === ".") note = `DUP ACK #${++dups} (still waiting for byte ${ack})`;
  else { note = `ACK up to ${ack}` + (who === "C" && W < 200 ? `, window shrinking (win ${W})` : ""); if (who === "C") dups = 0; }
  if (L === 0) last[who] = { ack: +ack, win: W };
  console.log(`${t.slice(6)}  ${who === "S" ? "S->C" : "C->S"} [${flags.padEnd(2)}] ${(s ? s + ":" + e : "ack " + ack).padEnd(10)} win ${String(W).padStart(3)}  ${note}`);
}

আসল রানের আউটপুট:

01.000000  S->C [. ] 1:1449     win 509  new data
01.000040  C->S [. ] ack 1449   win 501  ACK up to 1449
01.000300  S->C [. ] 2897:4345  win 509  GAP: bytes 1449:2897 not seen yet (lost or reordered)
01.000340  C->S [. ] ack 1449   win 501  DUP ACK #1 (still waiting for byte 1449)
01.000600  S->C [. ] 4345:5793  win 509  new data
01.000640  C->S [. ] ack 1449   win 501  DUP ACK #2 (still waiting for byte 1449)
01.000900  S->C [. ] 5793:7241  win 509  new data
01.000940  C->S [. ] ack 1449   win 501  DUP ACK #3 (still waiting for byte 1449)
01.031000  S->C [. ] 1449:2897  win 509  RETRANSMISSION of 1449:2897 (fast retransmit after 3 dup ACKs)
01.031040  C->S [. ] ack 7241   win 120  ACK up to 7241, window shrinking (win 120)
01.061000  S->C [P.] 7241:8689  win 509  new data
01.061040  C->S [. ] ack 8689   win   0  ZERO WINDOW: receiver buffer full, sender must stop
01.291000  S->C [. ] ack 1      win 509  WINDOW PROBE: are you still at win 0?
01.291040  C->S [. ] ack 8689   win   0  ZERO WINDOW: receiver buffer full, sender must stop
01.700000  C->S [. ] ack 8689   win 501  WINDOW UPDATE: win 501, sender may continue
01.730000  S->C [P.] 8689:10137 win 509  new data

Loss আর fast retransmit (০১.০০০০০০–০১.০৩১০৪০): প্রথম segment (১:১৪৪৯) এলো, client ack 1449 দিল। তারপর এলো ২৮৯৭:৪৩৪৫ — মাঝের ১৪৪৯:২৮৯৭ নেই, কোড তাই GAP লিখেছে (Wireshark লিখত “Previous segment not captured”). প্রতিটি পরের segment-এ client একই ack 1449 দিল — তিনটি DUP ACK. তৃতীয়টি পেয়েই সার্ভার timeout-এর অপেক্ষা না করে হারানো অংশটি আবার পাঠাল — প্রায় এক RTT (৩০ ms) পরে RETRANSMISSION of 1449:2897 (fast retransmit after 3 dup ACKs) (পর্ব ৩০)। Client-এর কাছে বাকি সব আগেই ছিল, তাই এক লাফে ack 7241 — ৫টি segment × ১৪৪৮ = ৭২৪০ বাইট.

Zero window (০১.০৩১০৪০–০১.৭৩০০০০): সেই একই ACK-এ window 120 — ১২০ × ১২৮ = ১৫,৩৬০ বাইট মাত্র; অ্যাপ পড়ছে না, buffer ভরছে। পরের segment-এর পরে win 0 — ZERO WINDOW. সার্ভার থামল, ২৩০ ms পরে একটি খালি WINDOW PROBE পাঠাল, উত্তর আবারও win 0. Zero window-এর প্রায় ৬৪০ ms পরে অ্যাপ ডেটা পড়ল, client নিজেই WINDOW UPDATE: win 501 পাঠাল, আর ৩০ ms পরে সার্ভার আবার পাঠাতে শুরু করল। এই বিরতি নেটওয়ার্কের দোষ নয় — প্রাপক অ্যাপের (পর্ব ৩১)। Capture না দেখলে এটিকেও “নেট ধীর” বলা হতো।

প্রমাণ থেকে PMTUD black hole ধরা

পর্ব ২০-এ black hole কীভাবে তৈরি হয় দেখেছেন; এবার দেখুন capture-এর প্রমাণ থেকে কীভাবে তা ধরা যায়। ঘটনা: একটি অফিসের ব্যবহারকারী (192.168.10.25) site-to-site VPN দিয়ে data center-এর একটি অভ্যন্তরীণ রিপোর্ট-সার্ভার (10.20.0.5, port 80) থেকে PDF নামাতে পারছেন না — পাতা খোলে, ডাউনলোড আটকে থাকে। নিচের capture আর কমান্ডগুলো উদাহরণ।

তদন্তের খাতা
কোথায় দেখা
প্রমাণ
অনুমান
  1. প্রথম capture — client-এ. Handshake নিখুঁত: SYN, SYN-ACK, ACK — তাই DNS, routing, firewall-এর port, সার্ভারের সার্ভিস — সব বাদ। দুই প্রান্তই mss 1460 ঘোষণা করেছে, কারণ দুজনের নিজের link-ই ১৫০০ MTU-র; মাঝের VPN-এর কথা তারা জানে না।
  2. আকার-নির্ভর লক্ষণ. ৯৫ বাইটের ছোট অনুরোধ গেল, সার্ভারের ছোট ACK-ও এলো (ack 96). কিন্তু তারপর ডেটা আর আসে না। ছোট packet চলে, বড় চলে না — এটিই আকার-নির্ভর সমস্যার ছাপ। এখন প্রশ্ন: সার্ভার কি আদৌ পাঠাচ্ছে?
  3. দ্বিতীয় capture — সার্ভারে. সার্ভার পাঠাচ্ছে! ১৪৪৮ বাইট ডেটা (+ ২০ IP + ২০ TCP + ১২ timestamp = ১৫০০) — আর একই segment আবার পাঠাচ্ছে প্রায় ০.২১, ০.৪২, ০.৮৫ সেকেন্ড ব্যবধানে, প্রতিবার দ্বিগুণ (RTO backoff). প্রতিবার একই আকার। Filter-এ icmp রাখা ছিল, তবু একটিও ICMP নেই — সার্ভার কখনো জানতে পারছে না যে packet বড়।
  4. ICMP-র খোঁজে — router-এ. Data center-এর VPN router-এর ভেতরের দিকের interface-এ capture: router ঠিকই প্রতিবার সার্ভারকে “need to frag (mtu 1400)” পাঠাচ্ছে। Router পাঠায়, সার্ভার পায় না — মাঝখানে সার্ভারের সামনের firewall (বা সার্ভারের নিজের firewall) “নিরাপত্তার জন্য” সব ICMP ফেলে দিচ্ছে। এটাই black hole.
  5. Client থেকে আকার মাপা. -M do মানে DF বিট দিয়ে পাঠানো। -s 1472 + ৮ (ICMP) + ২০ (IP) = ১৫০০ বাইট — অফিসের router (192.168.10.1) জানাল MTU ১৪০০, আর Linux সেটি মনে রেখে পরের চেষ্টা নিজেই আটকাল (message too long). -s 1372 + ২৮ = ১৪০০ — পৌঁছাল। এই দিকে ICMP আটকানো নেই বলেই client শিখতে পারল; সার্ভারের দিকে পারছে না।
  6. সমাধান আর যাচাই. আসল সমাধান: সার্ভারের দিকের firewall-এ ICMP type ৩, code ৪ ঢুকতে দেওয়া। সাথে বা বিকল্প হিসেবে VPN router-এ MSS clamping. তারপর আবার capture — যাচাই ছাড়া সমাধান শেষ নয়। এখন segment ১৩৪৮ বাইট: ১৪০০ − ২০ − ২০ − ১২ = ১৩৪৮. ডাউনলোড চলছে।

৮ · Capture-এর বাইরে — counter, পথ, নাম আর log

প্রায়ই capture লাগে না — kernel-এর হিসাব বা log-এর একটি লাইনই যথেষ্ট। পর্ব ৬-এর মৌলিক কমান্ডগুলোর পরের ধাপ:

টুলকী দেখায়কখন
mtr -rwn -c 100 <IP>প্রতি hop-এর loss % আর RTT, অনেকক্ষণ ধরেকোন hop-এর পরে loss শুরু — শুধু গন্তব্য পর্যন্ত টিকে থাকা loss-ই আসল (পর্ব ২০)
ss -tiপ্রতিটি TCP সংযোগের ভেতরের অবস্থা: rtt, rto, cwnd, retrans, mss, pmtuএকটি নির্দিষ্ট সংযোগ ধীর কেন
ip -s linkInterface-এর RX/TX errors, dropped, overrunতার, card বা driver-এর সমস্যা
ethtool eth0Link-এর গতি আর duplex, auto-negotiation১০০ Mb/s বা “Half” duplex — duplex mismatch-এর সন্দেহ
nstat -az, netstat -sKernel-এর protocol counter (TcpRetransSegs, TcpExtListenDrops…)পুরো যন্ত্রের প্রবণতা; netstat পুরোনো, nstat iproute2-র
dig +traceRoot থেকে authoritative পর্যন্ত নাম খোঁজার প্রতিটি ধাপকোন স্তরের DNS সার্ভার ভুল বলছে (পর্ব ৩৫)
curl -v, --resolve, -wসংযোগ, TLS, header; DNS এড়িয়ে নির্দিষ্ট সার্ভারে যাওয়া; প্রতিটি পর্বের সময়HTTP স্তরের যেকোনো সমস্যা
openssl s_clientTLS handshake, certificate chain, versionTLS-এর ত্রুটি (পর্ব ৪৮)
journalctl -u nginx, /var/log/nginx/error.logসার্ভিসের নিজের log502/504-এর আসল কারণ

curl-এর -w option একটি অনুরোধের সময়কে ভাগ করে দেখায় — কোন অংশে দেরি, তা এক লাইনে বোঝা যায় (উদাহরণ; সময়গুলো শুরু থেকে জমা হওয়া, সেকেন্ডে):

$ curl -o /dev/null -s -w 'dns %{time_namelookup}\ntcp %{time_connect}\ntls %{time_appconnect}\nttfb %{time_starttransfer}\ntotal %{time_total}\n' https://shop.example.com/
dns 0.004120
tcp 0.042310
tls 0.121877
ttfb 2.684532
total 2.701004

$ curl -sI --resolve shop.example.com:443:203.0.113.81 https://shop.example.com/   # DNS এড়িয়ে দ্বিতীয় সার্ভারটি সরাসরি পরীক্ষা
HTTP/2 200

পড়ুন: DNS ৪ ms; TCP সংযোগ শেষ ৪২ ms-এ (অর্থাৎ handshake প্রায় ৩৮ ms — এক RTT); TLS শেষ ১২২ ms-এ (আরও প্রায় ৮০ ms); কিন্তু প্রথম বাইট এলো ২.৬৮ সেকেন্ডে — TLS-এর পরে সার্ভার প্রায় ২.৫৬ সেকেন্ড “ভেবেছে”। নেটওয়ার্ক দ্রুত, সার্ভার ধীর। --resolve দিয়ে load balancer-এর পেছনের সার্ভারগুলো একটি একটি করে পরীক্ষা করা যায়, নাম আর certificate ঠিক রেখে।

একটি নির্দিষ্ট সংযোগের ভেতরে দেখতে ss -ti (উদাহরণ, কিছু ঘর বাদ দেওয়া):

$ ss -ti dst 203.0.113.80
ESTAB 0 0 192.168.0.105:51514 203.0.113.80:443
	 cubic wscale:7,7 rto:236 rtt:35.2/6.1 mss:1448 pmtu:1500 cwnd:10 ssthresh:7
	 bytes_retrans:4344 send 3.29Mbps retrans:0/3 minrtt:31.8 …

rtt:35.2/6.1 — গড় RTT আর তার ওঠানামা (ms); cwnd:10 — congestion window, segment-এ; ssthresh:7 — আগে loss হয়েছিল বলে নামানো সীমা (পর্ব ৩২); retrans:0/3 — এখন বাকি ০, মোট ৩টি retransmission, আর bytes_retrans:4344 = ৩ × ১৪৪৮. send 3.29Mbps হিসাবটি নিজে মেলান: cwnd × mss × ৮ ÷ rtt = ১০ × ১৪৪৮ × ৮ ÷ ০.০৩৫২ ≈ ৩.২৯ Mb/s — এই সংযোগ এখন এর বেশি পাঠাতে পারে না। (Throughput-এর পূর্ণ হিসাব পর্ব ৫৬-এ।)

এবার এই পাতার রানারেই প্রথম পরীক্ষাগুলো চালাই — একটি rootless container, বাইরের ইন্টারনেট নেই। স্ক্রিপ্টটি শুধু পড়ে, টুল আছে কি না আগে দেখে, private নয় এমন ঠিকানা ঢেকে দেয়; loopback-এ একটি খোলা port (perl-এর listener) আর একটি বন্ধ port-এ সংযোগের চেষ্টা করে, তারপর TCP counter পড়ে:

private() { case "$1" in 127.*|10.*|192.168.*|172.1[6-9].*|172.2[0-9].*|172.3[01].*) return 0;; esac; return 1; }
row() { printf '%-24s %-6s %s\n' "$1" "$2" "$3"; }
row CHECK RESULT DETAIL; row ----- ------ ------
up=""; for d in /sys/class/net/*; do n=${d##*/}; [ "$n" = lo ] && continue
  s=$(cat "$d/operstate"); c=$(cat "$d/carrier" 2>/dev/null || echo 0)
  { [ "$s" = up ] || { [ "$s" = unknown ] && [ "$c" = 1 ]; }; } && up="$up $n($s)"; done
[ -n "$up" ] && row "1 link up" PASS "${up# }" || row "1 link up" FAIL "no interface up"
a=$(ip -4 -o addr show scope global 2>/dev/null | awk '{print $2, $4}' | head -1)
set -- $a; private "${2%/*}" || a="$1 <host-IP>"
[ -n "$a" ] && row "2 IPv4 address" PASS "$a" || row "2 IPv4 address" FAIL "none (DHCP?)"
gw=$(ip route show default 2>/dev/null | awk '{print $3; exit}')
[ -n "$gw" ] && { private "$gw" || gw="<gateway-IP>"; row "3 default route" PASS "via $gw"; } || row "3 default route" FAIL "none"
ns=$(grep -c '^nameserver' /etc/resolv.conf 2>/dev/null)
[ "${ns:-0}" -gt 0 ] && row "4 resolv.conf" PASS "$ns nameserver line(s) (addresses hidden)" || row "4 resolv.conf" FAIL "no nameserver"
l=$(getent hosts localhost | awk '{print $1; exit}')
[ -n "$l" ] && row "5 getent localhost" PASS "$l" || row "5 getent localhost" FAIL "not resolved"
if command -v perl >/dev/null; then
  timeout 5 perl -MIO::Socket::INET -e '$s = IO::Socket::INET->new(LocalAddr => "127.0.0.1", LocalPort => 18080,
    Listen => 1, ReuseAddr => 1) or die; $c = $s->accept; close $c' & sleep 0.5
  timeout 3 bash -c 'exec 3<>/dev/tcp/127.0.0.1/18080' 2>/dev/null && row "6 TCP 127.0.0.1:18080" PASS "connected (listener up)" || row "6 TCP 127.0.0.1:18080" FAIL "no connect"
  wait
else row "6 TCP 127.0.0.1:18080" SKIP "perl নেই"; fi
timeout 3 bash -c 'exec 3<>/dev/tcp/127.0.0.1/9' 2>/dev/null; rc=$?
case $rc in 0) row "7 TCP 127.0.0.1:9" FAIL "unexpectedly open";; 124) row "7 TCP 127.0.0.1:9" FAIL "timeout: dropped/filtered?";;
  *) row "7 TCP 127.0.0.1:9" PASS "refused at once (closed port -> RST)";; esac
rs=$(awk '$1 == "Tcp:" { if (!h) { for (i = 1; i <= NF; i++) if ($i == "RetransSegs") k = i; h = 1 } else print $k }' /proc/net/snmp)
os=$(awk '$1 == "Tcp:" { if (!h) { for (i = 1; i <= NF; i++) if ($i == "OutSegs") k = i; h = 1 } else print $k }' /proc/net/snmp)
row "8 TCP retransmits" INFO "RetransSegs=$rs of OutSegs=$os"
command -v ss >/dev/null && ss -s | sed -n '1,2p' | sed 's/^/   ss -s: /' || echo "   ss নেই"

আসল রানের আউটপুট:

CHECK                    RESULT DETAIL
-----                    ------ ------
1 link up                PASS   tap0(unknown)
2 IPv4 address           PASS   tap0 10.0.2.100/24
3 default route          PASS   via 10.0.2.2
4 resolv.conf            PASS   5 nameserver line(s) (addresses hidden)
5 getent localhost       PASS   ::1
6 TCP 127.0.0.1:18080    PASS   connected (listener up)
7 TCP 127.0.0.1:9        PASS   refused at once (closed port -> RST)
8 TCP retransmits        INFO   RetransSegs=0 of OutSegs=8
   ss -s: Total: 1
   ss -s: TCP:   45 (estab 0, closed 45, orphaned 0, timewait 1)

১–৩, অংশ ৩-এর প্রথম ধাপগুলো: এখানে loopback ছাড়া একটিই interface — tap0, rootless container-এর virtual সংযোগ। এর state unknown (virtual interface-এ এটাই স্বাভাবিক), কিন্তু carrier ১, তাই PASS. ঠিকানা 10.0.2.100/24, default route 10.0.2.2 হয়ে — পর্ব ৬-এ দেখা সেই virtual gateway. দুটিই private ঠিকানা, তাই ঢাকা হয়নি।

৪ আর ৫ — নাম: resolv.conf-এ ৫টি nameserver লাইন (স্ক্রিপ্ট ইচ্ছা করে শুধু সংখ্যা দেখায়; glibc প্রথম ৩টিই ব্যবহার করে)। getent hosts localhost দিয়েছে ::1 — /etc/hosts থেকে, DNS ছাড়াই।

৬ আর ৭ — খোলা বনাম বন্ধ: perl-এর listener থাকায় port ১৮০৮০-তে সংযোগ হয়েছে। Port ৯-এ কেউ শোনে না, তাই kernel সাথে সাথে RST পাঠিয়েছে — refused at once. স্ক্রিপ্ট timeout (exit ১২৪) আলাদা করে ধরে, কারণ “refused” মানে “বাড়ি আছে, দরজা বন্ধ”, আর “timeout” মানে “চিঠির কোনো জবাবই নেই”।

৮ — counter: /proc/net/snmp-এর RetransSegs=0: loopback-এ loss হয় না। OutSegs-এর ছোট সংখ্যাটি এসেছে পরীক্ষা ৬ আর ৭-এর SYN, ACK, FIN আর RST থেকে — দুই প্রান্তই এই যন্ত্রে, তাই দুই দিকের segment-ই গোনা। এই counter আর ss -s-এর সংখ্যাগুলো রানভেদে সামান্য বদলায়। আসল সার্ভারে RetransSegs ÷ OutSegs অনুপাত সময়ের সাথে বাড়তে থাকলে loss-এর খোঁজ শুরু করার সময়।

আরও গভীরে: Linux-এ libpcap একটি AF_PACKET socket খোলে, আর kernel-এর সাথে একটি ভাগাভাগি করা ring buffer (TPACKET_V3) ব্যবহার করে, যাতে প্রতিটি packet-এর জন্য আলাদা system call না লাগে; filter-টি ক্লাসিক BPF হিসেবে socket-এ লাগানো হয়। আধুনিক Linux-এ eBPF-ভিত্তিক টুল (যেমন bcc-র tcpretrans, tcplife) কোনো packet কপি না করেই kernel-এর ভেতরের ঘটনা — কোন সংযোগে কখন retransmission হলো — সরাসরি দেখায়, যা ব্যস্ত সার্ভারে capture-এর চেয়ে অনেক সস্তা। আর বড় network-card-এর offload (TSO, GRO) চালু থাকলে host-এ নেওয়া capture-এ MTU-র চেয়ে বড় “packet” দেখা যায় — প্র ০২-এ বিস্তারিত।

৯ · গোপনীয়তা, নৈতিকতা আর একটি ভালো রিপোর্ট

একটি pcap ফাইল একটি খোলা ডায়েরির মতো: কে কখন কোন সার্ভারে গেছে, DNS-এ কোন নাম খুঁজেছে, এনক্রিপ্ট না করা protocol-এ পাসওয়ার্ড, cookie, ইমেইলের লেখা। HTTPS-এর যুগেও ঠিকানা, সময়, আকার আর অনেক সময় নাম (DNS, SNI) খোলা থাকে। তাই packet capture শুধু প্রযুক্তি নয়, দায়িত্বও:

ক্যাফে, হল বা প্রতিবেশীর Wi-Fi-তে অন্যের traffic দেখা “শেখার জন্য” হলেও অনৈতিক, আর বহু দেশে বেআইনি। শিখতে নিজের ল্যাপটপে দুটি VM বা একটি পুরোনো router দিয়ে ল্যাব বানান।

যে রিপোর্ট পড়ে অন্য দল কাজ শুরু করতে পারে

প্রায়ই অন্য কাউকে জানাতে হয় — ISP, সার্ভার-দল, vendor. “ইন্টারনেট স্লো, দেখুন” লিখলে উত্তর আসে “আমাদের দিকে সব ঠিক”। একটি প্রমাণসহ ছাঁচ (উদাহরণ):

শিরোনাম : shop.example.com — 10:15 থেকে HTTP 502, সব ব্যবহারকারী
প্রভাব   : অফিসের 40 জনের সবাই; মোবাইল ডেটা থেকেও একই
লক্ষণ    : ব্রাউজারে "502 Bad Gateway", server: nginx; 10/10 চেষ্টায়
সময়     : প্রথম অভিযোগ 10:17 (UTC+6); শেষ সফল অর্ডার 10:13
যা ঠিক আছে (প্রমাণসহ): link, DHCP, gateway, public IP, DNS (203.0.113.80),
           TCP 443 (nc), TLS 1.3 (s_client: Verification OK) — আউটপুট সংযুক্ত
পুনরুৎপাদন: curl -sI https://shop.example.com/  ->  HTTP/2 502
কী বদলেছে: আমাদের দিকে কিছু নয়; সার্ভার-দলের 10:14-এর deploy?
সংযুক্ত  : কমান্ডের আউটপুট (সময়সহ), 20 লাইনের ছোট pcap (শুধু এই host)
অনুরোধ  : proxy-র error log-এ 10:14-এর পরের upstream ত্রুটি দেখুন

রিপোর্টটি ব্যাখ্যা চাপিয়ে দেয় না; প্রমাণ দেয়, আর কী বাদ গেছে তা বলে। সার্ভার-দল proxy-র log খুলে হয়তো দেখবে connect() failed (111: Connection refused) while connecting to upstream — অ্যাপ সার্ভারটি deploy-এর পরে চালুই হয়নি। আর সমাধানের পরে একটি ছোট লেখা — কী হয়েছিল, কেন, কীভাবে ধরা পড়ল, আবার না ঘটতে কী করা হলো — দলের ভবিষ্যৎ incident-এর সবচেয়ে বড় সম্পদ।

১০ · AI-এর যুগে সমস্যা খোঁজা — সহকারী, বিচারক নয়

AI-কে tcpdump-এর আউটপুট বা error log দিলে সে দ্রুত সম্ভাব্য কারণের তালিকা দেয় — কাজের জিনিস। কিন্তু AI আপনার নেটওয়ার্ক দেখেনি, শুধু লেখা দেখেছে:

AI-এর সাধারণ ভুলকীভাবে ধরবেন
পুরোনো কমান্ড (ifconfig, netstat, route) বা অন্য OS-এর flagip, ss, nstat; man আর command -v দিয়ে যাচাই
Wireshark-এর display filter আর BPF capture filter গুলিয়ে ফেলা (tcpdump 'tcp.port == 443')ছোট capture-এ চালিয়ে দেখুন; tcpdump ভুল filter-এ সাথে সাথে syntax error দেয়
“Firewall বন্ধ করে দেখুন” বা “সব ICMP খুলে দিন / বন্ধ করুন”শুধু নির্দিষ্ট নিয়ম, নির্দিষ্ট সময়ের জন্য; ICMP-র দরকারি type রাখুন (পর্ব ২০, ৪৯)
একটি লক্ষণ দেখেই নিশ্চিত রায় (“retransmission মানেই ISP”)Zero window, offload, capture-এর জায়গা বিবেচনা; দুই প্রান্তের capture মেলান
হিসাবে ভুল (relative seq, window scale, MSS = MTU − ৪০ ভুলে যাওয়া)নিজে হিসাব করুন; এই পর্বের JS কোডে বসিয়ে দেখুন
বানানো RFC নম্বর বা Wireshark-এর অস্তিত্বহীন filter ঘরrfc-editor.org; Wireshark-এর Display Filter Reference
অন্যের নেটওয়ার্কে capture বা scan-এর পরামর্শশুধু নিজের বা লিখিত অনুমতির নেটওয়ার্ক; প্রশ্নেই সীমা বলে দিন

AI-কে capture দেখানোর আগে ব্যক্তিগত তথ্য সরান — public IP, hostname, cookie, token. তারপর এমনভাবে জিজ্ঞেস করুন:

আমি আমার অফিসের (আমি নেটওয়ার্ক অ্যাডমিন) Ubuntu 24.04 সার্ভার থেকে একটি client-এর সাথে TCP সংযোগের সমস্যা খুঁজছি। নিচে tcpdump -nn -r capture.pcap-এর ৪০টি লাইন দিলাম (ঠিকানা বদলে documentation IP বসিয়েছি), আর ss -ti-এর আউটপুট: [এখানে আউটপুট পেস্ট করুন] ১. লাইন নম্বর ধরে বলো কোথায় retransmission, dup ACK, zero window বা RST — আর কেন তুমি তা মনে করছ। ২. অন্তত দুটি বিকল্প ব্যাখ্যা দাও, আর প্রতিটি যাচাইয়ের জন্য শুধু দেখার কমান্ড (sudo দরকার হলে বলো, কিছু বদলাবে না)। ৩. Wireshark display filter আর tcpdump capture filter আলাদা করে লেখো। ৪. কোনো RFC-র কথা বললে নম্বর আর শিরোনাম দাও; নিশ্চিত না হলে বলো।

AI-এর পরামর্শ মানার আগে — চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • “ওয়েবসাইট খুলছে না” — কীভাবে খুঁজবেন? — স্তর ধরে: link, IP/DHCP, gateway, বাইরের IP, DNS, TCP port, TLS, HTTP status; প্রতিটির কমান্ড আর ফল দেখে সিদ্ধান্ত।
  • Capture filter আর display filter-এর পার্থক্য? — Capture filter (BPF) ধরার আগে বাছাই করে, বাদ পড়া packet হারায়; display filter (Wireshark) ধরার পরে শুধু দেখানো বাছাই করে।
  • Connection refused আর connection timed out-এর পার্থক্য? — Refused: host RST পাঠিয়েছে, port বন্ধ; timeout: কোনো উত্তর নেই — firewall ফেলে দিচ্ছে, host বন্ধ বা পথ নেই।
  • Promiscuous mode চালু করলেই কি পুরো LAN-এর traffic দেখা যায়? — না; switch অন্যের frame পাঠায় না। দরকার port mirroring (SPAN) বা TAP — অনুমতি নিয়ে।
  • Zero window দেখলে সমস্যা কার? — প্রাপকের — তার অ্যাপ buffer থেকে ধীরে পড়ছে; নেটওয়ার্কের loss নয়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১tcpdump আর BPF কোথা থেকে এলো, আর filter-কে kernel-এর ভেতরে চালানোর বুদ্ধিটি এত গুরুত্বপূর্ণ কেন?

tcpdump-এর জন্ম ১৯৮০-র দশকের শেষে, যুক্তরাষ্ট্রের Lawrence Berkeley Laboratory-তে — Van Jacobson, Craig Leres আর Steven McCanne-এর হাতে। একই সময়ে Van Jacobson TCP-র congestion control (পর্ব ৩২) নিয়ে কাজ করছিলেন; ১৯৮৬-এর ইন্টারনেটের “congestion collapse” বুঝতে আর নিজের নতুন algorithm যাচাই করতে তাঁর দরকার ছিল তারে আসলে কী যাচ্ছে তা দেখার একটি ভালো যন্ত্র। traceroute-ও তাঁরই লেখা (১৯৮৭-৮৮)। অর্থাৎ আজকের প্রধান সমস্যা-খোঁজার টুলগুলো জন্মেছিল একটি বাস্তব সংকটের তদন্ত থেকে।

প্রথম দিকের capture ব্যবস্থায় প্রতিটি packet kernel থেকে user-space প্রোগ্রামে কপি হতো, তারপর প্রোগ্রাম ঠিক করত রাখবে কি না। ব্যস্ত নেটওয়ার্কে এতে CPU ভরে যেত, আর packet হারাত — অর্থাৎ পর্যবেক্ষণ নিজেই সমস্যা তৈরি করত। McCanne আর Jacobson ১৯৯৩ সালের USENIX সম্মেলনে “The BSD Packet Filter” নামের প্রবন্ধে সমাধানটি প্রকাশ করেন: filter-কে একটি ছোট, সরল virtual machine-এর bytecode-এ রূপান্তর করে kernel-এর ভেতরে চালানো, packet কপি করার আগে। Register-ভিত্তিক এই নকশা আগের পদ্ধতিগুলোর চেয়ে বহুগুণ দ্রুত ছিল। পরে capture-এর অংশটি tcpdump থেকে আলাদা করে libpcap লাইব্রেরি বানানো হয়, যাতে Wireshark-সহ অন্য টুলও একই ক্ষমতা পায় আর একই filter-ভাষা বোঝে।

গল্পটি এখানে থামেনি। Linux ২০১৪ সালের দিকে BPF-কে অনেক বড় করে “extended BPF” (eBPF) বানায় — এখন শুধু packet বাছাই নয়, kernel-এর প্রায় যেকোনো জায়গায় নিরাপদে ছোট প্রোগ্রাম বসিয়ে মাপজোখ, firewall, load balancing পর্যন্ত চলে। মূল ধারণাটি একই থেকেছে: কাজটি তথ্যের কাছে নিয়ে যান, তথ্যকে কাজের কাছে নয়। নেটওয়ার্কের পর্যবেক্ষণে এর ব্যবহারিক শিক্ষা: সব সময় সরু filter দিন — এতে CPU বাঁচে, packet হারায় কম (tcpdump শেষে “packets dropped by kernel” দেখায়), আর অপ্রাসঙ্গিক ব্যক্তিগত তথ্যও ধরা পড়ে না।

মূল উপলব্ধি: ভালো পর্যবেক্ষণ-যন্ত্র নিজে যতটা সম্ভব কম বোঝা চাপায়। BPF filter-কে kernel-এর ভেতরে চালিয়ে সেটিই করেছিল — আর সেই একই ধারণা আজ eBPF হয়ে আধুনিক Linux পর্যবেক্ষণের ভিত্তি।

প্র ০২একটি সার্ভারে নেওয়া capture-এ ৬৫,০০০ বাইটের “packet” আর checksum যাচাই চালু করলে লাল রঙের “incorrect checksum” দেখা যাচ্ছে, অথচ MTU ১৫০০ আর সংযোগ ঠিকঠাক চলছে। এটি কি ভুল, নাকি capture-এর জায়গার একটি বৈশিষ্ট্য?

এটি প্রায় নিশ্চিতভাবে ভুল নয় — এটি আধুনিক network card-এর offload-এর ছাপ। ১০ Gb/s বা তার বেশি গতিতে প্রতিটি ১৫০০ বাইটের packet আলাদাভাবে CPU-তে বানালে CPU-ই বাধা হয়ে দাঁড়ায়। তাই kernel TCP-র একটি বড় খণ্ড (ধরুন ৬৪ KB) একবারে card-কে দেয়, আর card নিজে সেটি MSS-আকারের segment-এ কেটে, প্রতিটির header আর checksum বসিয়ে তারে পাঠায় — একে বলে TSO (TCP Segmentation Offload); সফটওয়্যার-রূপটি GSO. আসার দিকে উল্টোটা: card বা driver ছোট segment জোড়া লাগিয়ে বড় খণ্ড বানিয়ে ওপরে দেয় (GRO, LRO).

tcpdump কোথায় packet দেখে? Linux-এ বাইরে যাওয়ার packet-এর কপি নেওয়া হয় driver-এর হাতে যাওয়ার ঠিক আগে — অর্থাৎ card কাটার আগের বড় খণ্ডটিই capture-এ আসে। তাই “length 65160” দেখা যায়, যা তারে কখনো যায়নি। একই কারণে checksum offload চালু থাকলে kernel checksum-এর ঘর ফাঁকা বা আংশিক রাখে (card পরে বসাবে), আর যাচাই চালু থাকলে Wireshark সেই অসম্পূর্ণ মান দেখে “incorrect checksum” বলে। বাইরে যাওয়ার packet-এ এই সতর্কবার্তা সাধারণত অর্থহীন — এই কারণেই Wireshark এখন ডিফল্টভাবে TCP আর UDP-র checksum যাচাই বন্ধ রাখে। আসার দিকে GRO থাকলে tcpdump জোড়া লাগানো বড় খণ্ড দেখে।

তাহলে “তারে আসলে কী গেছে” কীভাবে দেখবেন? দুটি পথ। এক, পথের মাঝে, mirror port বা TAP থেকে আলাদা যন্ত্রে capture — সেখানে আসল ১৫০০-র packet. দুই, সাময়িকভাবে offload বন্ধ করে host-এ capture (ethtool -K eth0 tso off gro off — শুধু পরীক্ষার যন্ত্রে, কারণ এতে CPU-র খরচ বাড়ে)। শিক্ষাটি বড়: প্রতিটি capture একটি নির্দিষ্ট জায়গার সত্য, পুরো পথের নয়। Host-এ দেখা “বিশাল packet” আর “bad checksum” দিয়ে কেউ যদি সিদ্ধান্ত নেন যে card খারাপ, তিনি অকারণে হার্ডওয়্যার বদলাবেন।

মূল উপলব্ধি: Capture কোথায় নেওয়া, তা জানা ছাড়া capture পড়া যায় না। Host-এর capture দেখায় kernel যা দিয়েছে বা পেয়েছে; তারের সত্য দেখতে হলে তারের কাছে যেতে হয়।

প্র ০৩নতুনদের শেখানো হয় নিচ থেকে ওপরে খুঁজতে, অথচ অভিজ্ঞরা প্রায়ই মাঝখান থেকে (একটি ping বা curl দিয়ে) শুরু করেন। কোনটি ঠিক, আর half-split কখন বিপজ্জনক?

দুটিই ঠিক — ভিন্ন অবস্থায়। Bottom-up-এর সুবিধা নিশ্চয়তা: প্রতিটি স্তর নিচের স্তরের ওপর দাঁড়ায়, তাই নিচ থেকে একে একে প্রমাণ করে উঠলে কোনো অনুমান লাগে না। যিনি নেটওয়ার্ক ভালো চেনেন না, বা যেখানে কিছুই চলছে না (নতুন অফিস, নতুন cable), সেখানে এটি নিরাপদ। খরচ সময়ের: সমস্যা যদি অ্যাপ্লিকেশন স্তরে হয় — আর ব্যবহারকারীর অভিযোগের বড় অংশই তাই — তবে নিচের সব পরীক্ষা অকারণ।

Half-split-এর শক্তি তথ্যতত্ত্বে। প্রতিটি হ্যাঁ/না পরীক্ষা সর্বোচ্চ এক বিট তথ্য দেয়; আটটি সম্ভাব্য জায়গার মধ্যে একটি খুঁজতে অন্তত তিন বিট লাগে, আর মাঝখান থেকে ভাগ করলে ঠিক তিনটি পরীক্ষাই লাগে। অভিজ্ঞ ইঞ্জিনিয়ার তাই প্রথমে এমন পরীক্ষা বাছেন, যা সম্ভাবনা মোটামুটি সমান দুই ভাগে ভাগ করে — “বাইরের IP-তে ping যায়?” বা “curl -v কোথায় থামে?” একটি curl-ই DNS, TCP, TLS আর HTTP — চারটি স্তর একসাথে পরীক্ষা করে, আর আউটপুট দেখায় কোথায় থেমেছে।

বিপদ একটি জায়গায়: binary search তখনই কাজ করে, যখন প্রতিটি পরীক্ষার উত্তর নির্ভরযোগ্য। নেটওয়ার্কে বহু পরীক্ষা “মিথ্যা না” দেয়: ICMP আটকানো থাকলে ping ব্যর্থ, অথচ পথ চালু; traceroute-এর মাঝের hop-এ * * *, অথচ forward ঠিক (পর্ব ২০); load balancer-এর পেছনে একটি সার্ভার ভালো, আরেকটি খারাপ — একবার চলে, একবার চলে না। একটি ভুল “না” আপনাকে ভুল অর্ধেকে পাঠায়, আর তারপর যত সাবধানেই খুঁজুন, উত্তর সেখানে নেই। তাই ভালো অভ্যাস: প্রতিটি “না”-কে অন্য protocol বা অন্য টুলে মিলিয়ে নিন (ping ব্যর্থ? TCP 443 দেখুন), আর intermittent সমস্যায় একবারের পরীক্ষা নয়, অনেকবার মাপুন।

আরেকটি কৌশল তৃতীয় পথ: ভালোর সাথে তুলনা। “মোবাইল ডেটায় চলে, অফিসে চলে না” — এক বাক্যে অর্ধেক পৃথিবী বাদ গেল: সার্ভার ঠিক, সমস্যা অফিসের পথে।

মূল উপলব্ধি: পদ্ধতি বাছাই নির্ভর করে আপনি কতটা জানেন আর পরীক্ষাগুলো কতটা বিশ্বাসযোগ্য তার ওপর। Half-split সবচেয়ে দ্রুত — যদি প্রতিটি “না”-কে আপনি দ্বিতীয়বার যাচাই করেন।

প্র ০৪PMTUD black hole তিন দশক ধরে পরিচিত, তবু আজও প্রায়ই দেখা যায়। কেন এটি এত টিকে আছে, আর নেটওয়ার্কের জগৎ এর বিরুদ্ধে কী কী করেছে?

Path MTU Discovery এসেছিল RFC 1191-এ (১৯৯০)। এর পুরো ভরসা একটি ICMP বার্তার ওপর — Fragmentation Needed. সমস্যা হলো, ১৯৯০-এর দশকে ICMP-র অপব্যবহার (ping flood, smurf) দেখে বহু প্রতিষ্ঠান firewall-এ “সব ICMP বন্ধ” নিয়ম বসায়। ফলে PMTUD-র প্রতিক্রিয়া-পথ কেটে গেল, অথচ কেউ টের পেল না — কারণ সাধারণ অবস্থায় সব link ১৫০০-র, বার্তাটির দরকারই পড়ে না। সমস্যা দেখা দেয় শুধু পথে ছোট MTU এলে: PPPoE (১৪৯২), VPN আর tunnel (আরও কম)। ২০০০ সালে RFC 2923 TCP-র PMTUD সমস্যার তালিকায় black hole-কে প্রধান সমস্যা হিসেবে নথিভুক্ত করে।

এটি টিকে আছে তিনটি কারণে। এক, লক্ষণ বিভ্রান্তিকর: handshake, ছোট পাতা, ping — সব চলে, তাই “নেটওয়ার্ক তো ঠিক!”। দুই, দায়ী যন্ত্র আর ভুক্তভোগী আলাদা জায়গায়: ICMP আটকায় সার্ভারের firewall, ভোগেন দূরের VPN ব্যবহারকারী, আর যে router বার্তাটি পাঠায় সে কিছুই ভুল করছে না। তিন, নিরাপত্তার নামে বসানো নিয়ম কেউ সরাতে চান না।

প্রতিরক্ষা এসেছে কয়েক স্তরে। MSS clamping: tunnel বা PPPoE-র router TCP-র SYN-এ MSS-এর মান ছোট করে লিখে দেয়, যাতে দুই প্রান্ত শুরু থেকেই ছোট segment পাঠায় — বাসার বহু router-এ এটি ডিফল্ট চালু, কিন্তু শুধু TCP-কে বাঁচায়। Packetization Layer PMTUD (RFC 4821, ২০০৭; UDP-ভিত্তিক protocol-এর জন্য RFC 8899): প্রেরক ICMP-র ওপর নির্ভর না করে নিজেই নানা আকারের probe পাঠিয়ে দেখে কোনটি পৌঁছায়; Linux-এ net.ipv4.tcp_mtu_probing. QUIC (পর্ব ৩৩) ধরে নেয় পথ অন্তত ১২০০ বাইটের packet নেবে, আর বড় আকার নিজেই probe করে খুঁজতে পারে। আর নির্দেশিকাগুলো (যেমন ICMPv6-এর জন্য RFC 4890) স্পষ্ট বলে কোন ICMP কখনো আটকানো যাবে না — IPv6-এ “Packet Too Big” আটকালে black hole আরও নিশ্চিত, কারণ সেখানে router কখনো fragment করে না।

মূল উপলব্ধি: একটি নিয়ন্ত্রণ-বার্তার ওপর নির্ভরশীল নকশা তত ভালো, যত ভালো সেই বার্তার পথ। নিরাপত্তার নিয়ম লেখার সময় জানতে হয় কোন “অদরকারি” traffic আসলে অন্য কারও অপরিহার্য প্রতিক্রিয়া।

প্র ০৫নেটওয়ার্কের ইঞ্জিনিয়ার হিসেবে packet capture করার ক্ষমতা আপনার আছে। গোপনীয়তার দিক থেকে সেই ক্ষমতার সীমা কোথায় — আর এনক্রিপশন বাড়ায় সমস্যা খোঁজা কীভাবে বদলেছে?

বাস্তবের কয়েকটি ঘটনা সীমাটি স্পষ্ট করে। ২০১০ সালে Eric Butler “Firesheep” নামে একটি ব্রাউজার extension প্রকাশ করেন, যা একই খোলা Wi-Fi-তে অন্যদের এনক্রিপ্ট না করা session cookie ধরে দেখাত — জনপ্রিয় সামাজিক মাধ্যমগুলো তখনো শুধু লগইনের পাতা HTTPS-এ রাখত। উদ্দেশ্য ছিল সমস্যাটি প্রকাশ্যে আনা, আর এর পরে বড় সাইটগুলো পুরো সাইট HTTPS-এ নেওয়ার গতি বাড়ায়। একই বছর জানা যায়, Google-এর Street View গাড়িগুলো Wi-Fi নেটওয়ার্কের মানচিত্র বানানোর সময় খোলা Wi-Fi-এর payload ডেটাও সংগ্রহ করেছিল; বিভিন্ন দেশে তদন্ত আর জরিমানা হয়। আর ইউরোপের সর্বোচ্চ আদালত ২০১৬ সালের Breyer মামলায় বলে, নির্দিষ্ট পরিস্থিতিতে dynamic IP ঠিকানাও ব্যক্তিগত তথ্য। অর্থাৎ একটি pcap ফাইল আইনের চোখেও ব্যক্তিগত তথ্যের ভান্ডার হতে পারে।

তাই ক্ষমতার সীমা তিনটি প্রশ্নে: অনুমতি — এই নেটওয়ার্ক আর এই traffic দেখার অধিকার কি আমার কাজের অংশ, লিখিতভাবে? প্রয়োজন — সমস্যা খুঁজতে ঠিক কতটুকু লাগবে? প্রায়ই header-ই যথেষ্ট (ছোট snaplen), একটি host আর port-ই যথেষ্ট। রক্ষণাবেক্ষণ — ফাইল কোথায় থাকবে, কে দেখবে, কবে মুছবে? দায়িত্বশীল প্রতিষ্ঠানে এগুলো লিখিত নীতি।

এনক্রিপশন এই ছবি বদলে দিয়েছে। আজ ওয়েবের বেশিরভাগ traffic HTTPS, TLS 1.3 certificate-ও এনক্রিপ্ট করে, DNS-ও DoH/DoT-এ যাচ্ছে, আর ECH এলে SNI-ও লুকাবে। পথের মাঝের capture থেকে HTTP status বা URL আর দেখা যায় না। ফলে সমস্যা খোঁজা সরে যাচ্ছে প্রান্তে: client-এর curl -v, ব্রাউজারের developer tools, সার্ভারের log আর metric. নিজের যন্ত্রে নিজের সংযোগ পড়তে ব্রাউজার আর curl SSLKEYLOGFILE-এ session key লিখতে পারে, যা Wireshark-এ দিলে নিজের traffic খোলা যায় — শুধু নিজের যন্ত্রে, কারণ ওই ফাইল যার হাতে, সে সবই পড়তে পারে। মাঝের capture-এর কাজ এখন মূলত TCP আর IP স্তর: loss, RTT, window, RST, MTU — আর এগুলো দেখতে বিষয়বস্তু লাগেই না।

মূল উপলব্ধি: Capture-এর ক্ষমতা একটি আস্থা, অধিকার নয়। সবচেয়ে ভালো ইঞ্জিনিয়ার সবচেয়ে কম দেখে সমস্যা ধরেন — সরু filter, ছোট snaplen আর প্রান্তের log দিয়ে।

অনুশীলন

হাতে হিসাব, আউটপুট অনুমান, কমান্ড লেখা আর তদন্তের পরিকল্পনা — চারটিই করুন।

  1. হাতে হিসাব (tcpdump): নিচের তিনটি লাইন tcpdump -S -nn দিয়ে নেওয়া (-S = আসল, অর্থাৎ absolute sequence নম্বর)। Handshake-এ দুই প্রান্তই wscale 7 দিয়েছিল। (ক) Client-এর ISN কত ছিল? (খ) প্রথম লাইনে কত বাইট ডেটা, আর আপেক্ষিক seq কত হতো? (গ) তৃতীয় লাইনের window বাইটে কত? (ঘ) ACK কত দেরিতে এলো?
    09:40:01.200000 IP 192.0.2.10.50000 > 198.51.100.20.80: Flags [P.], seq 7000001:7000201, ack 9000001, win 502, length 200
    09:40:01.200050 IP 192.0.2.10.50000 > 198.51.100.20.80: Flags [P.], seq 7000201:7000301, ack 9000001, win 502, length 100
    09:40:01.242050 IP 198.51.100.20.80 > 192.0.2.10.50000: Flags [.], ack 7000301, win 250, length 0

    (ক) এই সংযোগে client-এর প্রথম ডেটা-বাইটের নম্বর ৭০,০০,০০১. SYN একটি নম্বর খায়, তাই ISN = ৭০,০০,০০১ − ১ = ৭০,০০,০০০ (ধরে নেওয়া হচ্ছে এটিই client-এর প্রথম ডেটা)।

    (খ) ৭০,০০,২০১ − ৭০,০০,০০১ = ২০০ বাইট (length 200-এর সাথে মেলে)। আপেক্ষিক রূপে seq 1:201; দ্বিতীয় লাইন seq 201:301, ১০০ বাইট।

    (গ) ২৫০ × ২⁷ = ২৫০ × ১২৮ = ৩২,০০০ বাইট. সার্ভারের window আগে বেশি থাকলে এটি কমে আসা — সার্ভারের অ্যাপ ধীরে পড়ছে কি না, নজর রাখার মতো।

    (ঘ) ack 7000301 দুটি segment একসাথে স্বীকার করছে (cumulative ACK, ৩০০ বাইট)। দেরি: ০১.২৪২০৫০ − ০১.২০০০৫০ = ৪২ ms দ্বিতীয় segment থেকে — প্রায় এক RTT (যদি সার্ভার delayed ACK-এ অপেক্ষা না করে থাকে)।

  2. আউটপুট অনুমান (BPF): চারটি packet: #১ TCP 192.0.2.10:50412 → 198.51.100.20:443 (SYN); #২ UDP 192.0.2.10:40001 → 192.0.2.53:53; #৩ ICMP 192.0.2.1 → 192.0.2.10; #৪ TCP 192.0.2.77:51000 → 192.0.2.10:22. Filter: 'tcp and not port 22 or icmp'. কোন packet মিলবে? Filter-টি C-র মতো (and আগে) পড়া হলে কি উত্তর বদলাত?

    pcap-filter-এ not আগে, তারপর বাম থেকে ডানে: ((tcp and (not port 22)) or icmp). #১: tcp, port ২২ নয় → মেলে। #২: udp → প্রথম অংশ মিথ্যা, icmp-ও নয় → মেলে না। #৩: icmp → মেলে। #৪: tcp, কিন্তু port ২২ → মেলে না। উত্তর #১ আর #৩.

    এখানে C-র নিয়মেও একই গঠন দাঁড়ায় ((tcp and not port 22) or icmp), তাই উত্তর বদলায় না — অগ্রাধিকারের পার্থক্য ধরা পড়ে তখন, যখন or আগে আর and পরে আসে (যেমন অংশ ৪-এর শেষ filter). নিশ্চিত হতে অংশ ৪-এর কোডে pkts আর filter বদলে চালিয়ে দেখুন।

  3. কমান্ড লিখুন: আপনার দায়িত্বের একটি Linux সার্ভারে মাঝে মাঝে নাম খোঁজা ব্যর্থ হচ্ছে। (ক) একটি tcpdump কমান্ড লিখুন: interface eth0, নাম বা port-এর নাম খুঁজবে না, শুধু resolver 192.0.2.53-এর সাথে DNS traffic, ৫০০টি packet, ফাইলে /tmp/dns.pcap. (খ) ফাইলটি Wireshark-এ খুলে NXDOMAIN উত্তরগুলো দেখার display filter, আর (গ) উত্তরই আসেনি এমন query খোঁজার একটি উপায় লিখুন।
    sudo tcpdump -i eth0 -nn -c 500 -w /tmp/dns.pcap 'host 192.0.2.53 and port 53'

    (ক) -nn জরুরি — নইলে tcpdump নিজেই DNS প্রশ্ন পাঠিয়ে capture দূষিত করত। port 53 UDP আর TCP দুটোই ধরে (বড় উত্তর TCP-তে যায়)। (খ) dns.flags.rcode == 3 — NXDOMAIN; সব ত্রুটি একসাথে দেখতে dns.flags.rcode != 0. (গ) Wireshark প্রতিটি query-র সাথে তার উত্তর জোড়া দেয়; উত্তরহীন query দেখতে dns.flags.response == 0 && !dns.response_in. সাথে প্রতিটি উত্তরের দেরি দেখতে dns.time > 1. কাজ শেষে ফাইলটি মুছে ফেলুন — এতে সার্ভারের সব নাম-খোঁজা আছে।

  4. পরিকল্পনা আর হিসাব (half-split): একটি অফিস থেকে data center পর্যন্ত পথে ১৬টি hop. কোথাও packet হারাচ্ছে। আপনি যেকোনো hop-এর পরের অংশে নির্ভরযোগ্য পরীক্ষা চালাতে পারেন (যেমন সেখানে রাখা একটি পরীক্ষা-যন্ত্রে TCP সংযোগ)। (ক) একে একে গেলে আর half-split-এ সবচেয়ে খারাপ ক্ষেত্রে কয়টি পরীক্ষা লাগবে? (খ) Half-split-এর প্রথম তিনটি পরীক্ষা কোন hop-এ হবে, যদি প্রথমটি সফল, দ্বিতীয়টি ব্যর্থ হয়? (গ) কেন শুধু ping ব্যবহার করলে হিসাবটি ভেঙে যেতে পারে?

    (ক) একে একে: সবচেয়ে খারাপ ক্ষেত্রে ১৫টি পরীক্ষা (১৬টি জায়গার মধ্যে ১৫টি বাদ দিলেই শেষটি নিশ্চিত)। Half-split: ⌈log₂ ১৬⌉ = ৪টি.

    (খ) প্রথম পরীক্ষা মাঝখানে — hop ৮-এর পরে। সফল, তাই সমস্যা ৯–১৬-এ। দ্বিতীয় পরীক্ষা তার মাঝখানে — hop ১২. ব্যর্থ, তাই সমস্যা ৯–১২-এ। তৃতীয় পরীক্ষা hop ১০-এ; ফল দেখে চতুর্থটি hop ৯ বা ১১-এ — চারটিতেই নির্দিষ্ট hop পাওয়া যায়।

    (গ) ICMP-র উত্তর অনেক router কম অগ্রাধিকারে আর হার-সীমা দিয়ে দেয়, কেউ একেবারেই দেয় না (পর্ব ২০)। তাই ping-এর “না” মানে loss না-ও হতে পারে; একটি ভুল “না” পুরো খোঁজকে ভুল অর্ধেকে পাঠায়। প্রতিটি ফল দ্বিতীয় পদ্ধতিতে (TCP, বা mtr-এ গন্তব্য পর্যন্ত টিকে থাকা loss) মিলিয়ে নিন, আর প্রতিটি পরীক্ষা সময়সহ লিখে রাখুন।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমনেটওয়ার্কের একটি সমস্যা পদ্ধতি মেনে খোঁজার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. লক্ষণ ঠিকঠাক লেখা — কে, কী, কোথায়, কবে থেকে, কী বদলেছে
  2. সমস্যাটি নিজে আবার ঘটিয়ে দেখা
  3. তথ্য দেখে একটি নির্দিষ্ট অনুমান দাঁড় করানো
  4. একবারে একটি জিনিস বদলে অনুমানটি পরীক্ষা করা
  5. সমাধানের পরে আবার পরীক্ষা করে নিশ্চিত হওয়া
  6. কী হয়েছিল আর কীভাবে ধরা পড়ল, লিখে রাখা

একটি Linux client-এর capture-এ দেখা যাচ্ছে: 192.0.2.10 থেকে 203.0.113.80:443-এ [S] গেল ০, ১, ৩ আর ৭ সেকেন্ডে, কোনো উত্তর নেই — না SYN-ACK, না RST, না ICMP. সবচেয়ে সম্ভাব্য ব্যাখ্যা কোনটি?

  • সার্ভার চালু, কিন্তু port 443-এ কোনো প্রোগ্রাম শুনছে না
  • পথের কোনো firewall SYN নিঃশব্দে ফেলে দিচ্ছে, বা সার্ভার বা তার পথ পৌঁছানো যাচ্ছে না
  • সার্ভারের receive buffer ভরা — zero window
  • DNS ভুল ঠিকানা দিচ্ছে বলে নাম খুঁজে পাওয়া যাচ্ছে না

নিচের কোনটি একটি বৈধ tcpdump capture filter (BPF)?

  • tcp port 443 and host 192.0.2.10
  • tcp.port == 443 && ip.addr == 192.0.2.10
  • http.response.code >= 400
  • tcp.analysis.retransmission

tcpdump-এর একটি লাইন: IP 198.51.100.20.80 > 192.0.2.10.51514: Flags [S.], seq 3870001234, ack 1546821001, win 65160, length 0. এর সঠিক ব্যাখ্যা কোনটি?

  • Client সংযোগ শুরু করছে, এটি প্রথম SYN
  • সার্ভার 1546821001 বাইট ডেটা পাঠিয়েছে
  • সার্ভারের SYN-ACK; client-এর ISN ছিল 1546821000
  • সার্ভার সংযোগ প্রত্যাখ্যান করছে

একজন ব্যবহারকারীর ল্যাপটপে: link চালু, ঠিকানা 192.168.0.105/24, gateway-তে ping সফল, ping 198.51.100.53 (একটি public IP) সফল, কিন্তু getent hosts shop.example.com কিছুই দেয় না আর ব্রাউজার বলে “server's DNS address could not be found”. পরের পদক্ষেপ কোনটি সবচেয়ে যুক্তিসঙ্গত?

  • Wi-Fi router restart করা আর তার বদলানো
  • সার্ভারের TLS certificate পরীক্ষা করা
  • সার্ভারের port 443-এ TCP সংযোগ পরীক্ষা করা
  • DNS — কোন resolver ব্যবহার হচ্ছে দেখা আর dig দিয়ে উত্তরের ধরন (NXDOMAIN, SERVFAIL, timeout) যাচাই

একটি Linux সার্ভারে tcpdump -i eth0 -nn 'tcp port 8080'-এ বাইরের client-দের SYN আসতে দেখা যাচ্ছে, কিন্তু সার্ভার কোনো SYN-ACK বা RST পাঠাচ্ছে না, আর ss -tln দেখাচ্ছে একটি প্রোগ্রাম 0.0.0.0:8080-এ শুনছে। সবচেয়ে সম্ভাব্য কারণ কী?

  • সার্ভারের নিজের firewall (netfilter) SYN-গুলো capture-এর পরে ফেলে দিচ্ছে
  • কোনো প্রোগ্রাম port 8080-এ শুনছে না
  • পথের কোনো router SYN হারিয়ে ফেলছে
  • Client-এর receive window শূন্য

একটি ডাউনলোডের capture-এ client বারবার Flags [.], ack 88001, win 0 পাঠাচ্ছে, সার্ভার মাঝে মাঝে খালি একটি segment পাঠাচ্ছে, আর কয়েক সেকেন্ড পরে client win 501 পাঠানোর পরে ডাউনলোড আবার চলছে। কোনো retransmission নেই। কী বোঝা যায়?

  • পথে ব্যাপক packet loss, ISP-র দোষ
  • Client-এর অ্যাপ ডেটা ধীরে পড়ছে — zero window; নেটওয়ার্ক দোষী নয়
  • PMTUD black hole — বড় packet হারাচ্ছে
  • সার্ভারের অ্যাপ্লিকেশন crash করেছে

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. পদ্ধতি: লক্ষণ (কে, কী, কোথায়, কবে থেকে, কী বদলেছে) → পুনরুৎপাদন → অনুমান → একবারে একটি পরিবর্তন → যাচাই → লিখে রাখা। সহজ জিনিস আগে।
  2. Bottom-up নিশ্চিত কিন্তু ধীর, top-down একটি অ্যাপের সমস্যায় ভালো, half-split দ্রুততম (⌈log₂ n⌉ পরীক্ষা) — যদি প্রতিটি “না” দ্বিতীয় পদ্ধতিতে মিলিয়ে নেন।
  3. ওয়েবসাইট না খুললে: link → IP → gateway → বাইরের IP → DNS → TCP 443 → TLS → HTTP status; প্রথম আসল ব্যর্থতাই উত্তর।
  4. Capture: libpcap + kernel-এর ভেতরে BPF filter; root লাগে; switch-এ অন্যের traffic দেখতে mirror বা TAP; Linux-এ tcpdump আগত packet দেখে firewall-এর আগে। Capture filter ধরার আগে, display filter ধরার পরে।
  5. ছাপ চিনুন: উত্তরহীন SYN = drop; সাথে সাথে RST = বন্ধ port; dup ACK + retransmission = loss; win 0 = ধীর প্রাপক; বড় packet হারায় = PMTUD black hole. Capture-এ ব্যক্তিগত তথ্য — অনুমতি, সরু filter, এনক্রিপ্ট আর মুছে ফেলা।

পরের পর্বে: সংযোগ চলছে, কিন্তু যত দ্রুত হওয়ার কথা তত নয় — কেন? Bandwidth-delay product, window আর buffer-এর tuning, iperf দিয়ে মাপা, আর throughput-এর সীমা হিসাব করা।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান