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

IPv6 — ঠিকানা, header, SLAAC আর রূপান্তর

IPv6 — Addressing, the Header, Neighbor Discovery, SLAAC & Transition

Taught in Bangla, this lesson explains why IPv6 was needed, writing and compressing 128-bit addresses, /48 and /64 prefixes, address types with no broadcast and multicast everywhere, EUI-64 and privacy interface IDs, the 40-byte header, extension headers and the 1280-byte rule, ICMPv6, Neighbor Discovery and SLAAC, transition with dual stack, tunnels and translation, and IPv6 security.

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

  • IPv6 কেন এলো, আর কেন তা ছড়াতে এত সময় লাগছে
  • যেকোনো IPv6 ঠিকানা ছোট থেকে বড় আর বড় থেকে canonical রূপে লেখা, prefix আর interface ID আলাদা করা
  • ঠিকানার ধরন চেনা — global, link-local, unique local, multicast, solicited-node, anycast — আর EUI-64 হাতে হিসাব করা
  • IPv6 header-এর প্রতিটি ঘর, extension header-এর শিকল, MTU ১২৮০ আর Path MTU Discovery
  • Neighbor Discovery, DAD, SLAAC, DHCPv6 আর IPv4 থেকে রূপান্তরের কৌশল — নিরাপত্তার দিকসহ

১ · কেন IPv6 — ঠিকানা ফুরিয়ে যাওয়ার গল্প

পর্ব ১৬-এ (ipv4-addressing.html) দেখেছেন, একটি IPv4 ঠিকানা ৩২ বিট। মোট ঠিকানা ২৩২ = ৪,২৯,৪৯,৬৭,২৯৬ — প্রায় ৪৩০ কোটি। ১৯৮০-এর দশকে, যখন ইন্টারনেটে কয়েক হাজার কম্পিউটার, তখন সংখ্যাটি অফুরন্ত মনে হয়েছিল। আজ পৃথিবীর মানুষই প্রায় ৮০০ কোটি, আর একেকজনের হাতে ফোন, ল্যাপটপ, স্মার্ট টিভি, অফিসে আরও কয়েকটি যন্ত্র।

ধরুন ঢাকার একটি পুরোনো মহল্লায় বাড়ির নম্বর মাত্র তিন অঙ্কের — ৯৯৯টির বেশি বাড়ি হলে নম্বর দেওয়ার উপায় নেই। তখন দুটি সমাধান। এক, একটি নম্বরের বাড়িতে দশটি পরিবার গাদাগাদি করে থাকা, আর গেটের দারোয়ান চিঠি ভাগ করে দেওয়া — এটাই NAT (পর্ব ১৯, nat.html). দুই, নম্বরের নিয়মটাই বদলে এত লম্বা করা যে আর কখনো ফুরোবে না — এটাই IPv6.

ঠিকানা ফুরোনোর ঘটনাটি ধাপে ধাপে ঘটেছে। ২০১১ সালের ফেব্রুয়ারিতে বিশ্বব্যাপী ঠিকানার ভান্ডার রাখা প্রতিষ্ঠান IANA তার শেষ IPv4 ব্লকগুলো পাঁচটি আঞ্চলিক রেজিস্ট্রির (RIR) মধ্যে ভাগ করে দেয়। বাংলাদেশ যে অঞ্চলের রেজিস্ট্রির আওতায়, সেই APNIC একই বছরের এপ্রিলে শেষ ব্লকের কড়া রেশনিংয়ে চলে যায়; ইউরোপ, আমেরিকা আর অন্য অঞ্চলের রেজিস্ট্রিও পরের কয়েক বছরে একই অবস্থায় পৌঁছায়। এখন নতুন প্রতিষ্ঠানকে IPv4 ঠিকানা সাধারণত অন্যের কাছ থেকে কিনতে বা ভাড়া নিতে হয়।

নতুন ঠিকানা-ব্যবস্থার কাজ শুরু হয় ১৯৯০-এর দশকের শুরুতে, “IPng” (next generation) নামে। ১৯৯৫ সালের ডিসেম্বরে প্রথম স্পেসিফিকেশন RFC 1883 প্রকাশিত হয়, ১৯৯৮ সালে RFC 2460, আর ২০১৭ সালে RFC 8200 IPv6-কে পূর্ণ Internet Standard করে। নাম IPv5 নয় কেন? Version নম্বর ৫ আগেই একটি পরীক্ষামূলক streaming protocol (ST) ব্যবহার করেছিল, তাই পরের নম্বর ৬ নেওয়া হয়।

IPv6 শুধু “বেশি ঠিকানা” নয়। নকশাকারীরা তিনটি লক্ষ্য রেখেছিলেন:

  • End-to-end আবার ফেরানো: প্রতিটি যন্ত্রের নিজস্ব global ঠিকানা থাকলে দুটি যন্ত্র সরাসরি কথা বলতে পারে — NAT-এর পেছনে লুকিয়ে থাকা আর port বদলের ঝামেলা লাগে না (end-to-end principle, পর্ব ৩)। ভিডিও কল, অনলাইন গেম আর peer-to-peer অ্যাপে এর সুবিধা সবচেয়ে বেশি।
  • সরল, দ্রুত header: নির্দিষ্ট ৪০ বাইটের header, checksum নেই, পথে packet ভাঙা নেই — router-এর কাজ কম।
  • নিজে নিজে কনফিগার: যন্ত্র নেটওয়ার্কে যুক্ত হয়েই router-এর ঘোষণা শুনে নিজের ঠিকানা বানাতে পারে; DHCP সার্ভার বাধ্যতামূলক নয়।

তাহলে এত ধীরে ছড়াচ্ছে কেন?

IPv6 আর IPv4 সরাসরি একে অপরের সাথে কথা বলতে পারে না — এটি নতুন একটি protocol, পুরোনোটির “আপডেট” নয়। তাই প্রতিটি router, firewall, সার্ভার, অ্যাপ আর কর্মীর প্রশিক্ষণ — সব জায়গায় খরচ। অন্যদিকে NAT আর ISP-র বড় আকারের NAT (CGNAT) দিয়ে IPv4 জোড়াতালি দিয়ে চলছে, তাই অনেক প্রতিষ্ঠান তাড়া অনুভব করেনি। ফল: কিছু দেশে আর বড় মোবাইল নেটওয়ার্কে IPv6 এখন ট্রাফিকের বড় অংশ বহন করে, আবার কোথাও খুবই কম।

সংখ্যা মুখস্থ করবেন না, নিজে দেখে নিন। IPv6 কত শতাংশ ব্যবহারকারী ব্যবহার করেন — তা কে, কীভাবে মাপছে তার ওপর নির্ভর করে, আর প্রতি মাসে বদলায়। নির্ভরযোগ্য সর্বজনীন মাপ পাবেন Google-এর IPv6 পরিসংখ্যান পাতায়, APNIC Labs-এর দেশভিত্তিক মাপে আর Cloudflare Radar-এ। বাংলাদেশেও কিছু মোবাইল অপারেটর আর ISP IPv6 চালু করেছে বলে জানা যায়, তবে কত গ্রাহক আসলে IPv6 পাচ্ছেন, তা এই সাইটগুলোর দেশভিত্তিক পাতায় দেখে নেওয়াই নিরাপদ — বই বা AI-এর বলা পুরোনো সংখ্যা নয়।

২ · ১২৮ বিটের ঠিকানা — লেখা, ছোট করা আর আবার বড় করা

১২৮ বিট মানে ১৬ বাইট। IPv4-এর মতো দশমিকে লিখলে ১৬টি সংখ্যা হতো — অসহনীয়। তাই IPv6 লেখা হয় hexadecimal-এ (০–৯ আর a–f): প্রতি ১৬ বিট একটি ঘর, ৪টি hex অঙ্ক, মোট ৮টি ঘর, মাঝে কোলন।

2001:0db8:acad:0001:0000:0000:0000:0010
└─┬┘ └─┬┘ └─┬┘ └─┬┘ └─┬┘ └─┬┘ └─┬┘ └─┬┘
  16   16   16   16   16   16   16   16  bits = 128 bits

মোট ঠিকানা ২১২৮ ≈ ৩.৪ × ১০৩৮. এই সংখ্যাটা কত বড়, তা কল্পনা করাই কঠিন — শুধু একটি /64 নেটওয়ার্কেই (পরের অংশ) ঠিকানা আছে ২৬৪ = ১,৮৪,৪৬,৭৪,৪০,৭৩,৭০,৯৫,৫১,৬১৬টি, যা পুরো IPv4 ইন্টারনেটের চার বিলিয়ন গুণেরও বেশি।

এই পর্বের সব global ঠিকানা 2001:db8::/32 থেকে নেওয়া — RFC 3849 অনুযায়ী এই ব্লক শুধু বই আর ডকুমেন্টেশনের উদাহরণের জন্য সংরক্ষিত, ইন্টারনেটে কখনো route হয় না। নিজের নোট, স্লাইড বা প্রশ্নপত্রেও এটিই ব্যবহার করুন।

ছোট করার তিন নিয়ম

  1. শুরুর শূন্য বাদ: প্রতিটি ঘরের বাঁয়ের শূন্যগুলো বাদ দেওয়া যায় — 0db8 → db8, 0010 → 10, 0000 → 0. ডানের শূন্য কখনো নয়: ab00 যা ছিল তাই থাকে।
  2. শূন্যের টানা সারি একবার ::: পরপর এক বা একাধিক শূন্য-ঘরকে :: দিয়ে বদলানো যায় — কিন্তু পুরো ঠিকানায় মাত্র একবার. দুবার দিলে পড়ার সময় বোঝা যাবে না কোন ফাঁকে কতগুলো শূন্য ছিল।
  3. Canonical রূপ (RFC 5952, ২০১০): একই ঠিকানার অনেক বৈধ লেখা হতে পারে, তাই একটি “আদর্শ” রূপ ঠিক করা হয়েছে — (ক) শুরুর শূন্য অবশ্যই বাদ, (খ) :: বসবে সবচেয়ে লম্বা শূন্য-সারিতে, সমান হলে প্রথমটিতে, (গ) মাত্র একটি শূন্য-ঘরকে :: করা চলবে না, (ঘ) hex অক্ষর ছোট হাতের।

নিচের ধাপগুলো পরীক্ষার সবচেয়ে প্রচলিত অনুশীলনটি দেখায় — দুটি সমান লম্বা শূন্য-সারিসহ একটি ঠিকানা। “পরে” চাপুন:

মূল ঠিকানা৮টি ঘর × ১৬ বিট
2001:0DB8:0000:0000:0001:0000:0000:00AB
  1    2    3    4    5    6    7    8   ← ঘর নম্বর
ছোট হাতের অক্ষরRFC 5952 §4.3
2001:0db8:0000:0000:0001:0000:0000:00ab
নিয়ম ১ — শুরুর শূন্য বাদ0000 হয় 0, খালি নয়
2001:db8:0:0:1:0:0:ab
শূন্যের সারি খোঁজাদুটি সারি, দুটিই ২ ঘর লম্বা
2001:db8:0:0:1:0:0:ab
         └A┘     └B┘
সারি A = ঘর ৩–৪ (২টি)   সারি B = ঘর ৬–৭ (২টি)
সমান লম্বা → প্রথমটি (A) পাবে ::
নিয়ম ২ — একবার ::canonical রূপ
2001:db8::1:0:0:ab
ভুল লেখা আর উল্টো পথবড় করা
2001:db8::1::ab      ✗ দুটি :: — অবৈধ
2001:db8:0:0:1::ab   ✓ বৈধ, কিন্তু canonical নয়
2001:db8::1:0:0:ab   ✓ canonical

বড় করা: আছে ৬টি ঘর → :: = ৮ − ৬ = ২টি শূন্য-ঘর
2001:0db8:0000:0000:0001:0000:0000:00ab
  1. মূল ঠিকানা। ৮টি ঘর, প্রতিটিতে ৪টি hex অঙ্ক = ১৬ বিট। কেউ বড় হাতের অক্ষরে লিখেছেন, শূন্যও পুরোটা লিখেছেন — বৈধ, কিন্তু পড়তে কষ্ট।
  2. ছোট হাতের অক্ষর। DB8 হলো db8, AB হলো ab. মান বদলায়নি; canonical নিয়মে hex অক্ষর ছোট হাতের হতে হয়, যাতে log খুঁজতে বা দুটি ঠিকানা তুলনা করতে সুবিধা হয়।
  3. প্রতিটি ঘরের শুরুর শূন্য বাদ। 0db8 থেকে db8, 0001 থেকে 1, 00ab থেকে ab. পুরো শূন্য-ঘর 0000 একটি 0 হয়ে থাকে — ঘরটি মুছে যায় না।
  4. শূন্যের টানা সারি খোঁজা। দুটি সারি পাওয়া গেল: ঘর ৩–৪ আর ঘর ৬–৭, দুটিই ২ ঘর লম্বা। RFC 5952-এর নিয়ম: সবচেয়ে লম্বা সারি; সমান হলে বাঁ দিকের প্রথমটি। তাই সারি A জিতল।
  5. একবার :: বসানো। ঘর ৩–৪-এর জায়গায় ::, বাকি সব যেমন ছিল: 2001:db8::1:0:0:ab. এটাই canonical রূপ — যেকোনো সঠিক টুল (যেমন C-এর inet_ntop) ঠিক এটাই ছাপবে।
  6. ভুল আর উল্টো পথ। দুটি :: অবৈধ, কারণ কোন ফাঁকে কয়টি শূন্য তা আর বোঝা যায় না। বড় করার কৌশল: যে কয়টি ঘর লেখা আছে গুনুন (এখানে ৬), ৮ থেকে বাদ দিন — ::-এর জায়গায় ততগুলো 0000 বসবে।

এবার কয়েকটি ঠিকানা একসাথে। নিচের ছোট টুলটি প্রতিটি ঠিকানাকে পুরো ৮ ঘরে বড় করে, তারপর ঠিক উপরের নিয়মে canonical রূপে ছোট করে, ধরন চিনে বলে, আর /64 ধরে prefix আর interface ID আলাদা করে। Run চাপুন:

// IPv6 address tool: expand, compress (RFC 5952), classify, split a /64.
function expand(s) {
  const a = s.toLowerCase(), [head, tail] = a.includes("::") ? a.split("::") : [a, null];
  const h = head ? head.split(":") : [], t = tail ? tail.split(":") : [];
  const fill = tail === null ? [] : Array(8 - h.length - t.length).fill("0");
  return [...h, ...fill, ...t].map(g => g.padStart(4, "0"));
}
function compress(full) {
  const g = full.map(x => x.replace(/^0+(?=.)/, ""));   // rule 1: drop leading zeros
  let best = -1, len = 1;                               // rule 2: longest zero run, length >= 2
  for (let i = 0; i < 8; i++) {
    let j = i; while (j < 8 && g[j] === "0") j++;
    if (j - i > len) { best = i; len = j - i; }          // ">" keeps the FIRST of equal runs
  }
  return best < 0 ? g.join(":") : g.slice(0, best).join(":") + "::" + g.slice(best + len).join(":");
}
function kind(f) {
  const n = parseInt(f[0], 16), z = f.slice(0, 7).every(x => x === "0000");
  if (z && f[7] === "0000") return "unspecified (::)";
  if (z && f[7] === "0001") return "loopback (::1)";
  if ((n & 0xff00) === 0xff00) return `multicast, scope ${f[0][3]} (${{1: "interface", 2: "link", 5: "site", e: "global"}[f[0][3]] ?? "?"})`;
  if ((n & 0xffc0) === 0xfe80) return "link-local unicast (fe80::/10)";
  if ((n & 0xfe00) === 0xfc00) return "unique local unicast (fc00::/7)";
  if (f[0] === "2001" && f[1] === "0db8") return "global unicast range, DOCUMENTATION 2001:db8::/32";
  if ((n & 0xe000) === 0x2000) return "global unicast (2000::/3)";
  return "other / reserved";
}
["2001:0DB8:0000:0000:0008:0800:200C:417A", "2001:db8:acad:1:0:0:0:10", "2001:db8:0:0:1:0:0:1",
 "2001:db8:0:1:1:1:1:1", "FE80:0000:0000:0000:0200:5EFF:FE00:5301", "fd12:3456:789a:1::1",
 "ff02:0:0:0:0:1:ff00:5301", "0:0:0:0:0:0:0:1", "::"].forEach(a => {
  const f = expand(a);
  console.log(`${a}\n  full : ${f.join(":")}\n  short: ${compress(f)}  -> ${kind(f)}`);
  if (!kind(f).includes("multicast") && f.slice(0, 7).some(x => x !== "0000"))
    console.log(`  /64  : prefix ${compress([...f.slice(0, 4), "0", "0", "0", "0"])}/64  IID ${f.slice(4).join(":")}`);
});

আউটপুট (প্রতিবার একই):

2001:0DB8:0000:0000:0008:0800:200C:417A
  full : 2001:0db8:0000:0000:0008:0800:200c:417a
  short: 2001:db8::8:800:200c:417a  -> global unicast range, DOCUMENTATION 2001:db8::/32
  /64  : prefix 2001:db8::/64  IID 0008:0800:200c:417a
2001:db8:acad:1:0:0:0:10
  full : 2001:0db8:acad:0001:0000:0000:0000:0010
  short: 2001:db8:acad:1::10  -> global unicast range, DOCUMENTATION 2001:db8::/32
  /64  : prefix 2001:db8:acad:1::/64  IID 0000:0000:0000:0010
2001:db8:0:0:1:0:0:1
  full : 2001:0db8:0000:0000:0001:0000:0000:0001
  short: 2001:db8::1:0:0:1  -> global unicast range, DOCUMENTATION 2001:db8::/32
  /64  : prefix 2001:db8::/64  IID 0001:0000:0000:0001
2001:db8:0:1:1:1:1:1
  full : 2001:0db8:0000:0001:0001:0001:0001:0001
  short: 2001:db8:0:1:1:1:1:1  -> global unicast range, DOCUMENTATION 2001:db8::/32
  /64  : prefix 2001:db8:0:1::/64  IID 0001:0001:0001:0001
FE80:0000:0000:0000:0200:5EFF:FE00:5301
  full : fe80:0000:0000:0000:0200:5eff:fe00:5301
  short: fe80::200:5eff:fe00:5301  -> link-local unicast (fe80::/10)
  /64  : prefix fe80::/64  IID 0200:5eff:fe00:5301
fd12:3456:789a:1::1
  full : fd12:3456:789a:0001:0000:0000:0000:0001
  short: fd12:3456:789a:1::1  -> unique local unicast (fc00::/7)
  /64  : prefix fd12:3456:789a:1::/64  IID 0000:0000:0000:0001
ff02:0:0:0:0:1:ff00:5301
  full : ff02:0000:0000:0000:0000:0001:ff00:5301
  short: ff02::1:ff00:5301  -> multicast, scope 2 (link)
0:0:0:0:0:0:0:1
  full : 0000:0000:0000:0000:0000:0000:0000:0001
  short: ::1  -> loopback (::1)
::
  full : 0000:0000:0000:0000:0000:0000:0000:0000
  short: ::  -> unspecified (::)

খেয়াল করার বিষয়গুলো: প্রথম ঠিকানা (RFC-র পুরোনো উদাহরণ) ঘর ৩–৪-এর শূন্য হারিয়ে 2001:db8::8:800:200c:417a হলো — 0800 থেকে শুধু বাঁয়ের শূন্য গেল, ডানের 00 রইল। তৃতীয়টিতে দুটি সমান সারি, প্রথমটি :: পেল — ঠিক stepper-এর মতো। চতুর্থটিতে শূন্য-ঘর মাত্র একটি, তাই কোনো :: নেই: 2001:db8:0:1:1:1:1:1. Link-local ঠিকানাটির interface ID 0200:5eff:fe00:5301 — মাঝের ff:fe দেখেই বোঝা যায় এটি MAC থেকে বানানো (অংশ ৫)। fd12:3456:789a:1::1 একটি unique local ঠিকানা; fd12:3456:789a অংশটি এখানে উদাহরণের জন্য বানানো, বাস্তবে এটি random হতে হয়। Multicast, loopback আর unspecified-এ /64 ভাগের অর্থ নেই, তাই ছাপা হয়নি।

Operating system নিজেও ঠিক এই কাজ করে: C-এর inet_pton লেখা ঠিকানাকে ১৬ বাইটে বদলায় (“presentation to network”), আর inet_ntop ১৬ বাইট থেকে canonical লেখা বানায়। নিচের প্রোগ্রাম আটটি লেখা ঠিকানা দিয়ে round trip করে, তারপর loopback ::1-এর ওপর একটি UDP বার্তা পাঠিয়ে নিজেই গ্রহণ করে (Linux container-এ চলে; বাইরের ইন্টারনেট লাগে না):

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(void) {
    const char *in[] = { "2001:0DB8:0000:0000:0008:0800:200C:417A", "2001:db8:0:0:1:0:0:1",
                         "2001:db8:0:1:1:1:1:1", "2001:db8::0:1", "fe80:0:0:0:0200:5eff:fe00:5301",
                         "0:0:0:0:0:0:0:1", "::ffff:192.0.2.33", "2001:db8::1::2" };
    for (size_t i = 0; i < sizeof in / sizeof in[0]; i++) {
        struct in6_addr a; char out[INET6_ADDRSTRLEN];
        if (inet_pton(AF_INET6, in[i], &a) != 1) { printf("%-40s -> invalid\n", in[i]); continue; }
        inet_ntop(AF_INET6, &a, out, sizeof out);
        printf("%-40s -> %s\n", in[i], out);
    }
    int s = socket(AF_INET6, SOCK_DGRAM, 0), c = socket(AF_INET6, SOCK_DGRAM, 0);
    if (s < 0 || c < 0) { perror("socket(AF_INET6)"); return 0; }
    struct sockaddr_in6 sa; memset(&sa, 0, sizeof sa);
    sa.sin6_family = AF_INET6; sa.sin6_addr = in6addr_loopback;   /* ::1, port 0 = any */
    socklen_t len = sizeof sa;
    if (bind(s, (struct sockaddr *)&sa, len) < 0) { printf("bind to ::1 failed: no IPv6 loopback here\n"); return 0; }
    getsockname(s, (struct sockaddr *)&sa, &len);
    sendto(c, "hello over IPv6", 15, 0, (struct sockaddr *)&sa, sizeof sa);
    char buf[64], who[INET6_ADDRSTRLEN]; struct sockaddr_in6 from; socklen_t fl = sizeof from;
    ssize_t n = recvfrom(s, buf, sizeof buf - 1, 0, (struct sockaddr *)&from, &fl);
    if (n < 0) { perror("recvfrom"); return 0; }
    buf[n] = '\0';
    inet_ntop(AF_INET6, &from.sin6_addr, who, sizeof who);
    printf("UDP on [::1]: got \"%s\" (%zd bytes) from [%s]\n", buf, n, who);
    close(s); close(c);
    return 0;
}

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

2001:0DB8:0000:0000:0008:0800:200C:417A  -> 2001:db8::8:800:200c:417a
2001:db8:0:0:1:0:0:1                     -> 2001:db8::1:0:0:1
2001:db8:0:1:1:1:1:1                     -> 2001:db8:0:1:1:1:1:1
2001:db8::0:1                            -> 2001:db8::1
fe80:0:0:0:0200:5eff:fe00:5301           -> fe80::200:5eff:fe00:5301
0:0:0:0:0:0:0:1                          -> ::1
::ffff:192.0.2.33                        -> ::ffff:192.0.2.33
2001:db8::1::2                           -> invalid
UDP on [::1]: got "hello over IPv6" (15 bytes) from [::1]

বাঁয়ে যেভাবে লেখা হয়েছিল, ডানে glibc-র inet_ntop-এর ছাপা canonical রূপ। বড় হাতের অক্ষর, শুরুর শূন্য আর ::0:1-এর মতো অপ্রয়োজনীয় লেখা — সব inet_pton মেনে নিয়েছে, কারণ এগুলো বৈধ; ফেরত লেখায় সব এক নিয়মে এসেছে। সমান দুটি সারির প্রথমটি :: পেয়েছে (2001:db8::1:0:0:1), একটি মাত্র শূন্য-ঘর রয়ে গেছে। ::ffff:192.0.2.33 একটি IPv4-mapped ঠিকানা — IPv6 socket-এর ভেতরে একটি IPv4 ঠিকানা বহন করার উপায়; RFC 5952 অনুযায়ী এর শেষ ৩২ বিট দশমিকে ছাপা হয়। দুটি :: থাকা ঠিকানা inet_pton সোজা invalid বলেছে। শেষ লাইনে AF_INET6 socket [::1]-এ bind করে নিজের পাঠানো ১৫ বাইট পেয়েছে — অর্থাৎ এই container-এ IPv6 loopback চালু আছে। IPv6 বন্ধ থাকা কোনো যন্ত্রে প্রোগ্রামটি “bind to ::1 failed” বলে থামত, crash করত না।

URL আর port-এ বন্ধনী: IPv6 ঠিকানার ভেতরেই কোলন আছে, তাই port লিখতে হলে ঠিকানাটি [ ]-এ রাখতে হয় — http://[2001:db8::1]:8080/. আর link-local ঠিকানা সব interface-এ একই fe80::/64-এ থাকে বলে, কোন interface দিয়ে যেতে হবে তা % দিয়ে বলতে হয়: fe80::1%eth0 — এটিকে বলে zone index (Windows-এ সংখ্যা, যেমন %12).

৩ · Prefix, /48 আর /64 — ঠিকানার ভেতরের মানচিত্র

IPv4-এর মতো IPv6-এও prefix length লেখা হয় / দিয়ে: 2001:db8:acad::/48 মানে সামনের ৪৮ বিট নেটওয়ার্কের পরিচয়। তবে IPv6-এ subnet mask (255.255.…) লেখার চল নেই, আর একটি সাধারণ LAN প্রায় সবসময় /64. একটি global unicast ঠিকানার সাধারণ গঠন:

│◄─────── 48 bits ────────►│◄─16─►│◄─────────── 64 bits ────────────►│
┌──────────────────────────┬──────┬──────────────────────────────────┐
│  global routing prefix   │subnet│           interface ID           │
│ (from the ISP: the site) │  ID  │    (the host inside the LAN)     │
└──────────────────────────┴──────┴──────────────────────────────────┘
       2001:0db8:acad        0001         0200:5eff:fe00:5301
  • Global routing prefix: ISP বা রেজিস্ট্রি থেকে পাওয়া অংশ — ইন্টারনেটের router-রা শুধু এটুকু দেখে প্রতিষ্ঠান পর্যন্ত পৌঁছে দেয়।
  • Subnet ID: প্রতিষ্ঠান নিজে ঠিক করে কোন LAN কোন নম্বর পাবে। /48 পেলে subnet ID ১৬ বিট — ২১৬ = ৬৫,৫৩৬টি /64 LAN.
  • Interface ID: শেষ ৬৪ বিট, LAN-এর ভেতরে একটি interface-এর পরিচয়। SLAAC ঠিক ৬৪ বিটের interface ID ধরে কাজ করে, তাই /64-এর চেয়ে ছোট LAN বানালে SLAAC চলে না।

ঠিকানাটিকে ঢাকার একটি পোস্টাল ঠিকানার মতো ভাবুন: global routing prefix হলো এলাকা (ধরুন “ধানমন্ডি”) — দেশের যেকোনো ডাকঘর শুধু এটুকু দেখেই চিঠি ঠিক দিকে পাঠায়; subnet ID হলো রোড নম্বর — এলাকার ভেতরের ভাগ; আর interface ID হলো বাড়ির নম্বর। পার্থক্য একটাই: IPv6-এ একটি “রোডে” বাড়ির নম্বর রাখার জায়গা ২৬৪টি — কখনো ফুরোবে না।

কে কত বড় ব্লক পায়, তা ISP-র নীতিনির্ভর: প্রতিষ্ঠান প্রায়ই /48, বাসার সংযোগ প্রায়ই /56 (২৫৬টি LAN) বা /60, মোবাইল ফোন সাধারণত একটি /64. RFC 6177 নির্দিষ্ট মাপ চাপায় না, তবে একাধিক LAN-এর জায়গা দিতে বলে।

একটি subnet পরিকল্পনা — হাতে করা উদাহরণ

ধরুন একটি পোশাক কোম্পানি ISP থেকে 2001:db8:acad::/48 পেয়েছে। তাদের ঢাকায় প্রধান অফিস, গাজীপুরে কারখানা আর চট্টগ্রামে গুদাম। IPv4-এর মতো (পর্ব ১৭, subnetting.html) “কোন subnet-এ কয়টি host” হিসাব করতে হয় না — প্রতিটি LAN-ই /64. কাজটা শুধু ১৬ বিটের subnet ID-কে বোধগম্যভাবে সাজানো। Hex-এর প্রতিটি অঙ্ক ৪ বিট (একটি nibble), তাই অঙ্ক ধরে অর্থ দিলে পড়া সহজ হয়:

subnet ID (16 bits) = S F V V
                      │ │ └─┴── VV = VLAN বা তলা: 00–ff
                      │ └────── F = কাজ: 0 অবকাঠামো, 1 কর্মী, 2 অতিথি Wi-Fi, 3 সার্ভার
                      └──────── S = সাইট: 1 ঢাকা, 2 গাজীপুর, 3 চট্টগ্রাম
LANsubnet IDPrefix
পুরো ঢাকা সাইট1xxx2001:db8:acad:1000::/52 (৪,০৯৬টি /64)
ঢাকা, কর্মীদের সব LAN11xx2001:db8:acad:1100::/56 (২৫৬টি /64)
ঢাকা, কর্মী, ৫ম তলা11052001:db8:acad:1105::/64
গাজীপুর কারখানা, অতিথি Wi-Fi22002001:db8:acad:2200::/64
চট্টগ্রাম, সার্ভার33002001:db8:acad:3300::/64

নিয়মটা দেখুন: prefix ৪ বিট করে বাড়লে (/48 → /52 → /56 → /60 → /64) ঠিকানায় একটি করে hex অঙ্ক “স্থির” হয়, আর প্রতি ধাপে ভাগ হয় ১৬টি করে। তাই সাইট-ভিত্তিক /52 ব্লক থাকলে ঢাকার router বাইরে মাত্র একটি route ঘোষণা করলেই চলে — route aggregation, যার হিসাব পর্ব ১৭-এ আর routing-এ যার ব্যবহার পর্ব ২২-এ। দুই router-এর মাঝের point-to-point link-এ অনেকে /127 ব্যবহার করেন (RFC 6164), আর router-এর loopback-এ /128.

৪ · ঠিকানার ধরন — broadcast নেই, multicast সবখানে

IPv6-এ ঠিকানা তিন জাতের: unicast (একজনের জন্য), multicast (একটি দলের জন্য) আর anycast (একই ঠিকানা কয়েক জায়গায়, packet যায় সবচেয়ে কাছেরটিতে)। আর broadcast নেই — “সবাইকে” পাঠানোর কাজ করে একটি multicast দল, যাতে সব যন্ত্র থাকে। প্রথম কয়েকটি বিট দেখেই ধরন চেনা যায়:

ধরনPrefixউদাহরণকোথায় কাজ করেIPv4-এ কাছাকাছি
Global unicast2000::/32001:db8:acad:1::10পুরো ইন্টারনেটে route হয়public ঠিকানা
Link-localfe80::/10fe80::1শুধু একই link-এ; router কখনো পাঠায় না। প্রতিটি IPv6 interface-এর একটি থাকে।169.254.0.0/16
Unique local (ULA)fc00::/7 (বাস্তবে fd00::/8)fd12:3456:789a:1::1প্রতিষ্ঠানের ভেতরে; ইন্টারনেটে route হয় না10.0.0.0/8 ইত্যাদি private
Loopback::1/128::1নিজের যন্ত্রের ভেতরে127.0.0.1
Unspecified::/128::“এখনো ঠিকানা নেই” — DAD-এর সময় উৎস হিসেবে0.0.0.0
Multicastff00::/8ff02::1দলের সব সদস্য; চতুর্থ hex অঙ্ক পরিসর (scope)224.0.0.0/4, broadcast
Documentation2001:db8::/322001:db8::1শুধু বই আর উদাহরণে192.0.2.0/24 ইত্যাদি

ULA-তে fd-এর পরের ৪০ বিট (Global ID) RFC 4193 অনুযায়ী random হওয়ার কথা, যাতে দুটি নেটওয়ার্ক VPN-এ জুড়লে ঠিকানা না মেলে (ছোট ল্যাব বা container-এ অবশ্য fd00::/64 দেখা যায় — অংশ ৭)।

Multicast — চেনা দলগুলো

Multicast ঠিকানার ff-এর পরের দুটি hex অঙ্কের দ্বিতীয়টি scope: 1 = interface-এর ভেতরে, 2 = link, 5 = site, 8 = প্রতিষ্ঠান, e = global. প্রতিদিনের কাজে সবচেয়ে বেশি আসে link-scope দলগুলো:

  • ff02::1 — link-এর সব node (IPv4-এর broadcast-এর সবচেয়ে কাছের জিনিস)
  • ff02::2 — link-এর সব router
  • ff02::1:2 — সব DHCPv6 সার্ভার ও relay
  • ff02::1:ffXX:XXXX — solicited-node দল: ঠিকানার শেষ ২৪ বিট বসিয়ে বানানো

Solicited-node দলটিই ARP-এর broadcast-এর বুদ্ধিমান বিকল্প। ARP-এ (পর্ব ১৮, dhcp-arp.html) “192.168.1.20 কার?” প্রশ্ন LAN-এর সব যন্ত্রের CPU-কে থামিয়ে পড়তে বাধ্য করে। IPv6-এ প্রশ্নটি যায় শুধু সেই দলে, যার সদস্য কেবল যাদের ঠিকানার শেষ ২৪ বিট মেলে — বাস্তবে প্রায় সবসময় একজনই।

পরীক্ষার হলে কাউকে খুঁজতে মাইকে পুরো নাম ডাকলে সবার মনোযোগ ভাঙে — এটা broadcast. তার বদলে যদি বলা হয় “যাদের রোল নম্বরের শেষ তিন অঙ্ক ৫৩০, শুধু তারা মাথা তুলুন” — হাজার জনের হলে হয়তো একজন মাথা তুলবেন, বাকিরা নিশ্চিন্তে লিখতে থাকবেন। Solicited-node multicast ঠিক এটাই: শেষ ২৪ বিট মেলানো একটি ছোট দল।

Ethernet-এ multicast পৌঁছায় একটি বিশেষ MAC-এ: 33:33-এর পরে IPv6 multicast ঠিকানার শেষ ৩২ বিট (RFC 2464). তাই ff02::1 যায় 33:33:00:00:00:01-এ, আর ff02::1:ff00:5301 যায় 33:33:ff:00:53:01-এ। পর্ব ১২-এ (ethernet-switching.html) দেখেছেন, 0x33-এর I/G বিট ১ — তাই NIC এটাকে group ঠিকানা হিসেবে চেনে, আর যে দলে যোগ দেয়নি সেই দলের frame hardware-এই ফেলে দেয়, CPU পর্যন্ত যায় না। কোন port-এ কোন দলের সদস্য, তা switch জানতে পারে MLD বার্তা শুনে (MLD snooping); বিস্তারিত পর্ব ২৬-এ।

Anycast-এর আলাদা কোনো prefix নেই — একটি সাধারণ unicast ঠিকানাই কয়েকটি জায়গা থেকে ঘোষণা করা হয়, আর routing নিজে থেকে কাছেরটিতে পাঠায়। বড় DNS সার্ভার আর CDN এভাবে কাজ করে (পর্ব ২৫)। একটি নির্দিষ্ট anycast ঠিকানা IPv6 নিজেই সংরক্ষণ করেছে: প্রতিটি subnet-এর interface ID সব-শূন্য ঠিকানাটি (যেমন 2001:db8:acad:1::) — Subnet-Router anycast, অর্থাৎ ওই subnet-এর যেকোনো router.

৫ · Interface ID — EUI-64 থেকে গোপনীয়তার ঠিকানা

শেষ ৬৪ বিট কোথা থেকে আসে? চারটি পথ: হাতে বসানো (সার্ভার আর router-এ, যেমন ::1, ::10), DHCPv6 সার্ভার, অথবা যন্ত্র নিজে বানায় — MAC থেকে (EUI-64) বা random. পুরোনো এবং পরীক্ষায় সবচেয়ে প্রচলিত পদ্ধতি modified EUI-64: ৪৮ বিটের MAC-কে ৬৪ বিট বানানো। পর্ব ১২-এর U/L বিট এখানে আবার কাজে আসে।

  1. MAC48 বিটকার্ডের ঠিকানা
  2. মাঝে ff:fe64 বিটদুই ভাগের মাঝে
  3. U/L উল্টানোbit 1০ ↔ ১
  4. Interface ID4 ঘরশেষ ৬৪ বিট
  5. ঠিকানাprefix + IIDlink-local, global
MAC: 00:00:5e:00:53:01ডকুমেন্টেশনের জন্য সংরক্ষিত MAC
00:00:5e : 00:53:01
└──┬───┘   └──┬───┘
 OUI (নির্মাতা)  কার্ডের নিজস্ব অংশ
প্রথম বাইট 0x00 = 0000 0000   U/L বিট = 0 (universal)
মাঝখানে ff:fe৪৮ + ১৬ = ৬৪ বিট
00:00:5e:ff:fe:00:53:01
U/L বিট উল্টানোপ্রথম বাইট XOR 0x02
0x00 = 0000 0000
             ↓ উল্টে
0x02 = 0000 0010
02:00:5e:ff:fe:00:53:01
১৬ বিটের ঘরে সাজানোশুরুর শূন্য বাদ
0200:5eff:fe00:5301
→ 200:5eff:fe00:5301
Prefix জোড়াlink-local আর global
fe80::/64            → fe80::200:5eff:fe00:5301
2001:db8:acad:1::/64 → 2001:db8:acad:1:200:5eff:fe00:5301
Solicited-node আর তার MACশেষ ২৪ বিট, তারপর শেষ ৩২ বিট
ঠিকানার শেষ ২৪ বিট: …fe00:5301  →  00 53 01
solicited-node:  ff02::1:ff00:5301
Ethernet MAC:    33:33 + শেষ ৩২ বিট = 33:33:ff:00:53:01
  1. শুরু MAC থেকে। 00:00:5e:00:53:01 — প্রথম ৩ বাইট নির্মাতার OUI, শেষ ৩ বাইট কার্ডের নিজস্ব। প্রথম বাইট 0x00-এর bit 1 (U/L) এখন ০, অর্থাৎ এটি নির্মাতার দেওয়া “universal” ঠিকানা।
  2. মাঝখানে ff:fe বসানো। OUI আর কার্ডের অংশের ঠিক মাঝখানে ১৬ বিট ff:fe ঢোকানো হলো — ৪৮ বিট হয়ে গেল ৬৪ বিট। এই fffe দেখেই পরে যে কেউ চিনতে পারে ঠিকানাটি MAC থেকে বানানো।
  3. U/L বিট উল্টানো। প্রথম বাইটের bit 1 উল্টে দেওয়া হলো (XOR 0x02): 00 থেকে 02. কেন? IPv6-এ এই বিট ১ মানে “বিশ্বব্যাপী অনন্য” — উল্টানোর ফলে হাতে বসানো ছোট ID (যেমন ::1) স্বাভাবিকভাবে ০ থাকে, লিখতে সুবিধা। Random MAC (02:…) হলে উল্টে 00 হতো।
  4. Interface ID তৈরি। ৮ বাইটকে চারটি ১৬-বিটের ঘরে সাজালে 0200:5eff:fe00:5301, শুরুর শূন্য বাদ দিলে 200:5eff:fe00:5301.
  5. Prefix জোড়া। fe80::/64-এর সাথে জুড়ে link-local ঠিকানা fe80::200:5eff:fe00:5301; router-এর ঘোষণা করা 2001:db8:acad:1::/64-এর সাথে জুড়ে global ঠিকানা। একই interface ID দুই জায়গায়।
  6. Solicited-node দল। ঠিকানার শেষ ২৪ বিট 00:53:01 বসিয়ে দল ff02::1:ff00:5301; তার Ethernet MAC 33:33 আর ঠিকানার শেষ ৩২ বিট — 33:33:ff:00:53:01. খেয়াল করুন, link-local আর global — দুই ঠিকানারই শেষ ২৪ বিট এক, তাই দুটির জন্য একটিই দল।

EUI-64-এর সমস্যা: আপনাকে চেনা যায়

MAC থেকে বানানো interface ID কখনো বদলায় না। আপনি বাসার Wi-Fi, অফিস, ক্যাফে — যেখানেই যান, prefix বদলায়, কিন্তু শেষ ৬৪ বিট একই। ফলে যেকোনো ওয়েবসাইট বা বিজ্ঞাপন নেটওয়ার্ক শুধু ঠিকানা দেখেই বুঝতে পারে “এই সেই যন্ত্র” — আর নির্মাতার OUI দেখে যন্ত্রের ব্র্যান্ডও। এই গোপনীয়তার সমস্যার দুটি সমাধান এসেছে:

🎲 Temporary (privacy) address

RFC 4941 (পরে RFC 8981): random interface ID, যা নিয়মিত বদলায় (দিনে একবারের মতো, OS-ভেদে)। বাইরের সংযোগ শুরু করতে এটিই ব্যবহার হয়। ফোন আর ল্যাপটপের OS-গুলোতে সাধারণত ডিফল্টভাবে চালু থাকে বলে জানা যায়।

temporary address

🔒 Stable privacy address

RFC 7217: prefix, interface আর একটি গোপন চাবি মিলিয়ে hash করে interface ID — একই নেটওয়ার্কে সবসময় একই (সার্ভার, firewall নিয়মে সুবিধা), কিন্তু নেটওয়ার্ক বদলালে সম্পূর্ণ আলাদা। RFC 8064 (২০১৭) EUI-64-এর বদলে এটিকেই ডিফল্ট হিসেবে সুপারিশ করে।

stable privacy

বাস্তবে একটি ল্যাপটপে প্রায়ই একসাথে কয়েকটি IPv6 ঠিকানা দেখবেন — একটি link-local, একটি stable global, আর এক বা একাধিক temporary global. এটা ভুল নয়, নকশাই এমন। কোন OS কোন পদ্ধতি ডিফল্ট রাখে, তা সংস্করণ আর সেটিং অনুযায়ী বদলায় (Linux-এ addr_gen_mode আর use_tempaddr, অংশ ৭) — নিজের যন্ত্রে দেখে নিন।

৬ · IPv6 header — ৪০ বাইট, extension header আর ১২৮০-র নিয়ম

পর্ব ১৬-এ IPv4 header দেখেছেন: ২০ থেকে ৬০ বাইট, ১৩টির মতো ঘর, options, checksum আর fragmentation-এর ঘর। IPv6-এর নকশাকারীরা সেখান থেকে যা খুব কম লাগে বা প্রতিটি router-কে ধীর করে, তা সরিয়ে দিয়েছেন। ফল — সবসময় ঠিক ৪০ বাইট, মাত্র ৮টি ঘর:

 0       4               12
┌───────┬───────────────┬───────────────────────────────────────┐
│  Ver  │ Traffic Class │               Flow Label              │
│  (4)  │      (8)      │                  (20)                 │
├───────┴───────────────┴───────┬───────────────┬───────────────┤
│      Payload Length (16)      │  Next Header  │   Hop Limit   │
│                               │      (8)      │      (8)      │
├───────────────────────────────┴───────────────┴───────────────┤
│                                                               │
│                   Source Address (128 bits)                   │
│                                                               │
├───────────────────────────────────────────────────────────────┤
│                                                               │
│                 Destination Address (128 bits)                │
│                                                               │
└───────────────────────────────────────────────────────────────┘
  • Version (৪ বিট): সবসময় ৬. (Ethernet-এ IPv6 চেনা যায় EtherType 0x86DD দেখে।)
  • Traffic Class (৮ বিট): IPv4-এর ToS-এর মতো — ৬ বিট DSCP (অগ্রাধিকার, পর্ব ২৬) আর ২ বিট ECN (যানজটের সংকেত)।
  • Flow Label (২০ বিট): একই “প্রবাহ”-এর (যেমন একটি ভিডিও কলের) সব packet-কে একই লেবেল দেওয়া যায়, যাতে router বা load balancer পুরো header ঘেঁটে না দেখেও সেগুলোকে একই পথে রাখতে পারে (RFC 6437). অনেক যন্ত্র এখনো এটি শূন্য রাখে বা উপেক্ষা করে।
  • Payload Length (১৬ বিট): header-এর পরের বাইটের সংখ্যা (extension header সহ) — IPv4-এর মতো মোট দৈর্ঘ্য নয়। তাই সর্বোচ্চ ৬৫,৫৩৫; এর চেয়ে বড় “jumbogram”-এর জন্য আলাদা ব্যবস্থা আছে।
  • Next Header (৮ বিট): এর পরে কী আসছে — TCP (6), UDP (17), ICMPv6 (58), নাকি কোনো extension header. IPv4-এর Protocol ঘরের জায়গা নিয়েছে।
  • Hop Limit (৮ বিট): IPv4-এর TTL-এর সৎ নাম — প্রতিটি router ১ কমায়, ০ হলে ফেলে দিয়ে ICMPv6 Time Exceeded পাঠায় (traceroute এভাবেই কাজ করে, পর্ব ২০, icmp.html).
  • উৎস আর গন্তব্য ঠিকানা: ১৬ + ১৬ = ৩২ বাইট — header-এর ৮০%.

হিসাব মিলিয়ে নিন: ৪ + ৮ + ২০ + ১৬ + ৮ + ৮ = ৬৪ বিট = ৮ বাইট, সাথে ৩২ বাইট ঠিকানা — মোট ৪০ বাইট।

বিষয়IPv4IPv6কেন বদলাল
Header-এর মাপ২০–৬০ বাইট (IHL ঘর লাগে)ঠিক ৪০ বাইটHardware-এ দ্রুত, নির্দিষ্ট জায়গায় ঘর
Header checksumআছে, প্রতি hop-এ নতুন হিসাব (TTL বদলায় বলে)নেইLink-এর CRC আর TCP/UDP checksum ভুল ধরে; router-এর কাজ কমে
Fragmentationউৎস আর পথের router দুজনেই ভাঙতে পারেশুধু উৎস, Fragment extension header দিয়েRouter-এর বোঝা কমানো; PMTUD-র ওপর ভরসা
OptionsHeader-এর ভেতরেআলাদা extension header-এবেশিরভাগ router-কে এগুলো পড়তে হয় না
TTLTime To LiveHop Limitনাম আর কাজ মিলল — সময় নয়, hop গোনা
UDP checksumঐচ্ছিকসাধারণত বাধ্যতামূলকIP header-এ checksum নেই বলে ঠিকানা-সহ যাচাই transport-এ
ঠিকানা থেকে MACARP (broadcast)ICMPv6 Neighbor Discovery (multicast)অংশ ৭

Extension header — Next Header-এর শিকল

IPv4-এর options-এর জায়গায় IPv6-এ আছে আলাদা extension header: প্রতিটির ভেতরে আবার একটি Next Header ঘর, যা পরেরটির দিকে আঙুল তোলে — ঠিক একটি শিকলের মতো। শেষ কড়িতে থাকে TCP বা UDP. একটি ভাঙা (fragmented) TCP packet-এর উদাহরণ:

┌──────────────────┐   ┌──────────────────────┐   ┌──────────────────┐
│ IPv6 header      │   │ Fragment header      │   │ TCP segment      │
│ Next Header = 44 ├──►│ Next Header = 6      ├──►│ (data)           │
└──────────────────┘   └──────────────────────┘   └──────────────────┘
   0 = Hop-by-Hop   43 = Routing   44 = Fragment   50 = ESP   51 = AH
  60 = Destination Options   58 = ICMPv6   59 = আর কিছু নেই   6 = TCP   17 = UDP

নিয়ম অনুযায়ী পথের router শুধু Hop-by-Hop Options header দেখতে পারে; বাকিগুলো গন্তব্যের জন্য। এতে সাধারণ packet দ্রুত যায়। তবে বাস্তবে একটি দাম আছে: অনেক firewall আর router অচেনা বা লম্বা extension header-এর শিকল পেলে packet ফেলে দেয় (RFC 7872-এ এর পরিমাপ আছে), তাই নতুন protocol সাধারণত এর ওপর ভরসা করে না।

MTU ১২৮০ আর Path MTU Discovery

পথের কোনো link-এর MTU যদি packet-এর চেয়ে ছোট হয়, IPv4 router তখন packet ভেঙে পাঠাতে পারে। IPv6 router কখনো ভাঙে না — packet ফেলে দেয়, আর উৎসকে একটি ICMPv6 Packet Too Big বার্তা পাঠায়, যাতে লেখা থাকে “এই link-এর MTU এত”। উৎস তখন ছোট packet পাঠায়, প্রয়োজনে নিজে Fragment header দিয়ে ভাঙে। এই পদ্ধতির নাম Path MTU Discovery (IPv6-এর জন্য RFC 8201). আর সবাই যাতে নিশ্চিন্তে শুরু করতে পারে, তাই নিয়ম: IPv6 চলে এমন প্রতিটি link কমপক্ষে ১২৮০ বাইটের packet বহন করবে (RFC 8200). এর চেয়ে ছোট MTU-র link-কে নিচের স্তরে নিজেই টুকরো করে আবার জুড়তে হবে।

“নিরাপত্তার জন্য সব ICMP বন্ধ” — IPv6-এ এটি নেটওয়ার্ক ভাঙে। Packet Too Big বার্তা firewall আটকে দিলে উৎস কখনো জানবে না packet কেন হারাচ্ছে — ছোট পাতা খোলে, বড় ফাইল বা ছবি আটকে থাকে (“PMTU black hole”). Neighbor Discovery-ও ICMPv6 — বন্ধ করলে LAN-ই চলবে না। RFC 4890 বলে কোন ICMPv6 বার্তা অবশ্যই চলতে দিতে হবে আর কোনগুলো সীমিত করা যায়; firewall নিয়ম লেখার আগে সেটি দেখে নিন (firewall-এর বিস্তারিত পর্ব ৪৯)।

৭ · ICMPv6, Neighbor Discovery আর SLAAC

IPv4-এ ICMP ছিল “সহকারী” — ping আর ত্রুটির খবর। ICMPv6 (RFC 4443) তার চেয়ে অনেক বড় দায়িত্ব নিয়েছে: ARP, ঠিকানা কনফিগারেশন আর router খোঁজার কাজ এখন ICMPv6-এর একটি অংশ — Neighbor Discovery Protocol (NDP, RFC 4861). পাঁচটি বার্তা মনে রাখলেই চলে:

ICMPv6 typeবার্তাকে → কাকেকাজIPv4-এ যার জায়গায়
133Router Solicitation (RS)host → ff02::2“কোনো router আছেন?”DHCP Discover-এর অংশ
134Router Advertisement (RA)router → ff02::1 (নিয়মিত বা RS-এর উত্তরে)prefix, default router, hop limit, MTU, M/O পতাকাDHCP-র gateway আর subnet তথ্য
135Neighbor Solicitation (NS)যে কেউ → solicited-node দল বা সরাসরি“এই ঠিকানার MAC কী?”, DAD, প্রতিবেশী বেঁচে আছে কি নাARP request
136Neighbor Advertisement (NA)মালিক → প্রশ্নকারী“ঠিকানাটি আমার, MAC এই”ARP reply
137Redirectrouter → host“ওই গন্তব্যে আমার চেয়ে ভালো পথ আছে”ICMP Redirect

একটি সুন্দর নিরাপত্তা-কৌশল: সব NDP বার্তা পাঠানো হয় Hop Limit = ২৫৫ দিয়ে, আর গ্রহণকারী ২৫৫ না পেলে বার্তাটি ফেলে দেয়। কোনো router পার হলে মান কমে যেত — তাই ২৫৫ মানে বার্তাটি নিশ্চয়ই একই link থেকে এসেছে; দূরের কেউ ইন্টারনেট দিয়ে নকল RA পাঠাতে পারে না। (একই link-এর ভেতরের নকল RA-র কথা অংশ ৯-এ।)

DAD — ঠিকানা নেওয়ার আগে “এটা কি কারও?”

কোনো unicast ঠিকানা ব্যবহারের আগে host সেটিকে tentative (পরীক্ষাধীন) রাখে আর Duplicate Address Detection চালায়: উৎস :: (কারণ এখনো তার কোনো ঠিকানা নেই) দিয়ে ঠিকানাটির solicited-node দলে একটি NS পাঠায় — “fe80::… কি কারও?” ডিফল্টভাবে একবার পাঠায় আর প্রায় ১ সেকেন্ড অপেক্ষা করে। কেউ NA দিয়ে বললে “আমার” — ঠিকানাটি duplicate, ব্যবহার হবে না (Linux-এ dadfailed চিহ্ন পড়ে)। উত্তর না এলে ঠিকানাটি ব্যবহারযোগ্য হয়।

নতুন ভাড়াটে বাসায় নামফলক লাগানোর আগে সিঁড়িঘরে জোরে জিজ্ঞেস করলেন, “৪-বি নম্বর কি কেউ নিয়েছেন?” কিছুক্ষণ কেউ সাড়া না দিলে ফলক লাগালেন। কেউ বললে “আমরা আছি” — অন্য নম্বর খুঁজতে হবে।

SLAAC — বুট থেকে global ঠিকানা

SLAAC (Stateless Address Autoconfiguration, RFC 4862)-এ কোনো সার্ভার কাউকে ঠিকানা “দেয়” না, কোনো তালিকাও রাখে না — router শুধু prefix ঘোষণা করে, আর প্রতিটি host নিজে ঠিকানা বানায়। এজন্যই নাম “stateless”. ধরুন PC2 (MAC 00:00:5e:00:53:02) একটি LAN-এ যুক্ত হলো, যেখানে router R (fe80::1) আছে:

  1. PC2…53:02নতুন যুক্ত
  2. SwitchLANএকই link
  3. Router Rfe80::1prefix ঘোষণা করে
PC2-এর অবস্থা
link-local
global
default router
multicast দল
DNS
Interface চালুEUI-64 থেকে link-local
interface ID = 200:5eff:fe00:5302      (অংশ ৫-এর নিয়মে)
tentative    = fe80::200:5eff:fe00:5302
যোগ দিল দলে: ff02::1 (সবাই), ff02::1:ff00:5302 (solicited-node)
DAD: Neighbor SolicitationICMPv6 type 135, hop limit 255
Ethernet  dst 33:33:ff:00:53:02   src 00:00:5e:00:53:02
IPv6      src ::   dst ff02::1:ff00:5302
ICMPv6    NS target = fe80::200:5eff:fe00:5302
→ ~১ সেকেন্ড অপেক্ষা
কোনো NA আসেনিঠিকানা এখন ব্যবহারযোগ্য
fe80::200:5eff:fe00:5302  tentative → preferred
এখন এই ঠিকানা দিয়ে link-এ কথা বলা যায়
Router SolicitationICMPv6 type 133
Ethernet  dst 33:33:00:00:00:02
IPv6      src fe80::200:5eff:fe00:5302   dst ff02::2 (সব router)
ICMPv6    RS, option: source MAC 00:00:5e:00:53:02
Router AdvertisementICMPv6 type 134
IPv6      src fe80::1   dst ff02::1 (সবাই)
ICMPv6    RA  cur hop limit 64   M=0  O=1   router lifetime 1800 s
  prefix  2001:db8:acad:1::/64  L=1 A=1
          valid 2592000 s (৩০ দিন)  preferred 604800 s (৭ দিন)
  MTU     1500      source MAC 00:00:5e:00:53:fe
Global ঠিকানা তৈরি + DADprefix + interface ID
2001:db8:acad:1::/64 + 200:5eff:fe00:5302
= 2001:db8:acad:1:200:5eff:fe00:5302  (tentative)
DAD: NS src :: → ff02::1:ff00:5302 … উত্তর নেই → preferred
বাকি তথ্যO=1 → DHCPv6 Information-Request
default route: ::/0 via fe80::1 dev eth0
O=1 → DHCPv6 Information-Request → ff02::1:2  (DNS সার্ভার কে?)
(অথবা RA-র ভেতরের RDNSS option থেকেই DNS — RFC 8106)
  1. Interface চালু। PC2 নিজের MAC থেকে interface ID বানাল আর fe80:: জুড়ে একটি link-local ঠিকানা তৈরি করল — কিন্তু এখনো tentative, ব্যবহার করা যাবে না। সাথে যোগ দিল দুটি multicast দলে: ff02::1 আর নিজের solicited-node দল ff02::1:ff00:5302; দ্বিতীয় দলটির কথা switch-কে জানাতে একটি MLD report পাঠায়।
  2. DAD-এর NS. উৎস ::, গন্তব্য নিজের solicited-node দল, Ethernet-এ 33:33:ff:00:53:02. প্রশ্ন: “fe80::200:5eff:fe00:5302 কি কারও?” Hop limit ২৫৫. এবার ডিফল্টভাবে প্রায় ১ সেকেন্ড অপেক্ষা।
  3. কেউ সাড়া দিল না। তাই ঠিকানাটি অনন্য — preferred হলো। এখন PC2 link-এ কথা বলতে পারে, যদিও ইন্টারনেটের জন্য এখনো কোনো ঠিকানা নেই।
  4. Router Solicitation. নিয়মিত ঘোষণার অপেক্ষা না করে PC2 সব router-এর দল ff02::2-এ জিজ্ঞেস করল; উৎস এখন তার নতুন link-local ঠিকানা।
  5. Router Advertisement. R ঘোষণা করল: prefix 2001:db8:acad:1::/64, A=1 (“এটা দিয়ে নিজে ঠিকানা বানাতে পারেন”), L=1 (“এই prefix এই link-এই আছে”), router lifetime ১৮০০ সেকেন্ড (“আমাকে default router রাখুন”), আর পতাকা M=0, O=1: ঠিকানা SLAAC দিয়ে, কিন্তু DNS-এর মতো বাকি তথ্য DHCPv6 থেকে।
  6. Global ঠিকানা। Prefix আর একই interface ID জুড়ে 2001:db8:acad:1:200:5eff:fe00:5302. এটিও প্রথমে tentative; আবার DAD চলে। Solicited-node দল একই, কারণ শেষ ২৪ বিট এক। উত্তর নেই — preferred.
  7. প্রস্তুত। Default route হলো router-এর link-local ঠিকানা fe80::1 — IPv6-এ এটাই নিয়ম, global ঠিকানা বদলালেও next hop বদলায় না। O=1 বলে PC2 DHCPv6-এ শুধু “অন্যান্য তথ্য” চাইল (DNS সার্ভার)। কোনো সার্ভার PC2-এর ঠিকানা মনে রাখেনি — পুরো প্রক্রিয়া stateless.

M আর O পতাকা, DHCPv6 আর prefix delegation

RA-তেঠিকানা আসেDNS ও অন্যান্যনাম
M=0, O=0SLAACRA-র RDNSS option (বা হাতে)শুধু SLAAC
M=0, O=1SLAACDHCPv6DHCPv6 stateless
M=1DHCPv6 সার্ভার দেয় (সার্ভার তালিকা রাখে)DHCPv6DHCPv6 stateful

দুটি বাস্তব সূক্ষ্মতা। এক, DHCPv6 (এখন RFC 8415) default router জানায় না — সেটি সবসময় RA থেকেই আসে; তাই “শুধু DHCPv6, RA বন্ধ” নেটওয়ার্ক কাজ করে না। দুই, সব OS stateful DHCPv6 সমর্থন করে না — Android stateful DHCPv6 দিয়ে ঠিকানা নেয় না বলে বহুল জানা; তাই মিশ্র যন্ত্রের নেটওয়ার্কে SLAAC সাধারণত রাখতেই হয়। আর ISP-র দিকে DHCPv6-এর আরেকটি বড় কাজ prefix delegation: বাসার router ISP-র কাছে একটি পুরো prefix (ধরুন /56) চেয়ে নেয়, তারপর নিজের প্রতিটি LAN-এ তা থেকে একটি /64 ঘোষণা করে।

Simulator: SLAAC, DAD-এর সংঘাত আর প্রতিবেশী খোঁজা

নিচের simulator প্রথমে তিনটি ডকুমেন্টেশন-MAC থেকে EUI-64, solicited-node দল আর তার 33:33 MAC হিসাব করে। তারপর একটি LAN-এ PC2-কে দুবার চালু করে — প্রথমবার এটি একটি clone করা virtual machine, যার MAC ভুলবশত PC1-এর সাথে এক (বাস্তবে VM কপি করার সাধারণ ভুল); দ্বিতীয়বার নতুন MAC দিয়ে। শেষে PC2 প্রতিবেশী PC1-এর MAC খোঁজে:

// EUI-64, solicited-node and a SLAAC + Neighbor Discovery run on one link (deterministic).
const hx = n => n.toString(16);
function eui64(mac) {                                   // modified EUI-64 interface ID
  const b = mac.split(":").map(x => parseInt(x, 16));
  b.splice(3, 0, 0xff, 0xfe); b[0] ^= 0x02;              // insert ff:fe, flip the U/L bit
  return [0, 2, 4, 6].map(i => hx(b[i] * 256 + b[i + 1])).join(":");
}
function snm(iid) {                                     // solicited-node group + its 33:33 MAC
  const g = iid.split(":").map(x => x.padStart(4, "0")), t = g[2].slice(2) + g[3];
  return [`ff02::1:ff${t.slice(0, 2)}:${hx(parseInt(t.slice(2), 16))}`,
          `33:33:ff:${t.slice(0, 2)}:${t.slice(2, 4)}:${t.slice(4)}`];
}
for (const m of ["00:00:5e:00:53:01", "00:00:5e:00:53:02", "02:00:5e:00:53:aa"])
  console.log(`MAC ${m} -> IID ${eui64(m)} -> ${snm(eui64(m)).join("  ")}`);
const P = "2001:db8:acad:1:", PC1 = "00:00:5e:00:53:01", owner = { "fe80::1": "00:00:5e:00:53:fe" }; // router R ...
owner["fe80::" + eui64(PC1)] = owner[P + eui64(PC1)] = PC1;   // ... and PC1 are already on the link
function dad(addr) {
  const [g, m] = snm(addr.split(":").slice(-4).join(":"));
  console.log(`  DAD: NS src=:: dst=${g} (${m}) target=${addr}`);
  if (owner[addr]) { console.log(`  NA to ff02::1 from ${owner[addr]} -> DUPLICATE, stop`); return false; }
  console.log("  no NA within 1 s -> address is unique"); return true;
}
function boot(name, mac) {
  const iid = eui64(mac), ll = "fe80::" + iid, ga = P + iid;
  console.log(`\n${name} up, MAC ${mac}, tentative ${ll}`);
  if (!dad(ll)) return; owner[ll] = mac;
  console.log(`  RS: src=${ll} dst=ff02::2 (33:33:00:00:00:02)\n  RA: src=fe80::1 dst=ff02::1 M=0 O=1, prefix ${P}:/64 A=1, router life 1800 s`);
  if (!dad(ga)) return; owner[ga] = mac;
  console.log(`  ready: ${ga}/64, default router fe80::1`);
}
boot("PC2 (cloned VM, same MAC as PC1)", PC1);
boot("PC2 (after giving it a new MAC)", "00:00:5e:00:53:02");
const [g, m] = snm(eui64(PC1)), dst = P + eui64(PC1);
console.log(`\nPC2 -> ${dst}: neighbour cache miss`);
console.log(`  NS: src=${P + eui64("00:00:5e:00:53:02")} dst=${g} (${m})\n  NA: from ${owner[dst]} S=1 O=1 -> cache ${dst} = ${owner[dst]} REACHABLE`);

আউটপুট (প্রতিবার একই):

MAC 00:00:5e:00:53:01 -> IID 200:5eff:fe00:5301 -> ff02::1:ff00:5301  33:33:ff:00:53:01
MAC 00:00:5e:00:53:02 -> IID 200:5eff:fe00:5302 -> ff02::1:ff00:5302  33:33:ff:00:53:02
MAC 02:00:5e:00:53:aa -> IID 0:5eff:fe00:53aa -> ff02::1:ff00:53aa  33:33:ff:00:53:aa

PC2 (cloned VM, same MAC as PC1) up, MAC 00:00:5e:00:53:01, tentative fe80::200:5eff:fe00:5301
  DAD: NS src=:: dst=ff02::1:ff00:5301 (33:33:ff:00:53:01) target=fe80::200:5eff:fe00:5301
  NA to ff02::1 from 00:00:5e:00:53:01 -> DUPLICATE, stop

PC2 (after giving it a new MAC) up, MAC 00:00:5e:00:53:02, tentative fe80::200:5eff:fe00:5302
  DAD: NS src=:: dst=ff02::1:ff00:5302 (33:33:ff:00:53:02) target=fe80::200:5eff:fe00:5302
  no NA within 1 s -> address is unique
  RS: src=fe80::200:5eff:fe00:5302 dst=ff02::2 (33:33:00:00:00:02)
  RA: src=fe80::1 dst=ff02::1 M=0 O=1, prefix 2001:db8:acad:1::/64 A=1, router life 1800 s
  DAD: NS src=:: dst=ff02::1:ff00:5302 (33:33:ff:00:53:02) target=2001:db8:acad:1:200:5eff:fe00:5302
  no NA within 1 s -> address is unique
  ready: 2001:db8:acad:1:200:5eff:fe00:5302/64, default router fe80::1

PC2 -> 2001:db8:acad:1:200:5eff:fe00:5301: neighbour cache miss
  NS: src=2001:db8:acad:1:200:5eff:fe00:5302 dst=ff02::1:ff00:5301 (33:33:ff:00:53:01)
  NA: from 00:00:5e:00:53:01 S=1 O=1 -> cache 2001:db8:acad:1:200:5eff:fe00:5301 = 00:00:5e:00:53:01 REACHABLE

প্রথম তিন লাইন EUI-64 ক্যালকুলেটর: 00:00:5e:00:53:01 থেকে 200:5eff:fe00:5301 — stepper-এর হাতে করা হিসাবের সাথে হুবহু মিল। তৃতীয় MAC 02:… locally administered, তাই উল্টে প্রথম বাইট 00 হয়েছে আর ID শুরু হয়েছে 0: দিয়ে। প্রথম boot-এ clone করা PC2-এর tentative ঠিকানা PC1-এর ঠিকানার সাথে হুবহু এক; DAD-এর NS পেয়ে PC1 ff02::1-এ NA দিয়েছে (প্রশ্নকারীর উৎস ::, তাই উত্তর যায় সবার দলে) — PC2 থেমে গেছে, RS পর্যন্তও যায়নি। সমাধান: VM-কে নতুন MAC দেওয়া। দ্বিতীয় boot-এ পুরো SLAAC সফল: DAD → RS → RA → global ঠিকানা → আবার DAD. শেষে ঠিকানা-রেজোলিউশন: PC2-এর neighbour cache-এ PC1 নেই, তাই NS গেল PC1-এর solicited-node দলে (33:33:ff:00:53:01 — অন্য কোনো যন্ত্রের NIC এই frame নেবেই না), আর PC1 সরাসরি NA দিয়ে MAC জানাল। S=1 মানে “আপনার প্রশ্নের উত্তর”, O=1 মানে “cache-এর পুরোনো তথ্য এটি দিয়ে বদলে দিন”।

এবার একটি আসল Linux যন্ত্র দেখি। এই পাতার bash কোড যে container-এ চলে, সেখানে IPv6 আছে কি না জানা ছিল না — তাই স্ক্রিপ্টটি আগে ip আছে কি না দেখে, তারপর kernel-এর কাঁচা তালিকা /proc/net/if_inet6 পড়ে নিজেই ঘরগুলো ব্যাখ্যা করে। কিছুই বদলায় না, শুধু পড়ে:

# IPv6 on this Linux container: addresses, routes, and the kernel's raw address table.
if command -v ip >/dev/null; then
  echo "== ip -6 addr";  ip -6 addr
  echo "== ip -6 route"; ip -6 route
else
  echo "ip command not found - falling back to /proc"
fi
f=/proc/net/if_inet6
[ -r "$f" ] || { echo "$f missing: IPv6 is disabled or not available here"; exit 0; }
echo "== $f decoded (columns: address ifindex prefixlen scope flags device)"
while read -r addr idx plen scope flags dev; do
  full=$(echo "$addr" | sed 's/..../&:/g; s/:$//')
  case $scope in 00) sc=global;; 10) sc=host;; 20) sc=link;; *) sc="0x$scope";; esac
  fl=""
  (( 16#$flags & 0x80 )) && fl+="permanent "
  (( 16#$flags & 0x40 )) && fl+="tentative "
  (( 16#$flags & 0x20 )) && fl+="deprecated "
  (( 16#$flags & 0x08 )) && fl+="dadfailed "
  (( 16#$flags & 0x01 )) && fl+="temporary "
  echo "$dev  $full/$((16#$plen))  ifindex=$((16#$idx))  scope=$sc  flags=0x$flags ${fl:-(none: has lifetimes)}"
done < "$f"
echo "== per-interface settings"
for d in /proc/sys/net/ipv6/conf/*/; do
  n=$(basename "$d")
  echo "$n: addr_gen_mode=$(cat "$d/addr_gen_mode" 2>/dev/null || echo ?)  use_tempaddr=$(cat "$d/use_tempaddr" 2>/dev/null || echo ?)  mtu=$(cat "$d/mtu" 2>/dev/null || echo ?)"
done

আসল রানের আউটপুট (আপনার রানে hex অঙ্কগুলো আলাদা হবে):

== ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 state UNKNOWN qlen 1000
    inet6 fd00::40e7:54ff:fefc:234a/64 scope global dynamic mngtmpaddr 
       valid_lft 86400sec preferred_lft 14400sec
    inet6 fe80::40e7:54ff:fefc:234a/64 scope link 
       valid_lft forever preferred_lft forever
== ip -6 route
fd00::/64 dev tap0 proto kernel metric 256 expires 86399sec pref medium
fe80::/64 dev tap0 proto kernel metric 256 pref medium
default via fe80::2 dev tap0 proto ra metric 1024 expires 1799sec hoplimit 64 pref medium
== /proc/net/if_inet6 decoded (columns: address ifindex prefixlen scope flags device)
lo  0000:0000:0000:0000:0000:0000:0000:0001/128  ifindex=1  scope=host  flags=0x80 permanent 
tap0  fd00:0000:0000:0000:40e7:54ff:fefc:234a/64  ifindex=2  scope=global  flags=0x00 (none: has lifetimes)
tap0  fe80:0000:0000:0000:40e7:54ff:fefc:234a/64  ifindex=2  scope=link  flags=0x80 permanent 
== per-interface settings
all: addr_gen_mode=0  use_tempaddr=0  mtu=1280
default: addr_gen_mode=0  use_tempaddr=0  mtu=1280
lo: addr_gen_mode=0  use_tempaddr=-1  mtu=65536
tap0: addr_gen_mode=0  use_tempaddr=0  mtu=65520

এই container-এ IPv6 পুরোপুরি চালু। lo-তে ::1/128, scope host. tap0 হলো container-কে বাইরের সাথে জোড়ার একটি software interface; তাতে দুটি ঠিকানা, দুটিরই শেষ ৬৪ বিট 40e7:54ff:fefc:234a — মাঝের ff:fe বলছে এটি EUI-64. উল্টো হিসাবে (ff:fe সরিয়ে 40-এর U/L বিট উল্টে) MAC ছিল 42:e7:54:fc:23:4a — software-এ বানানো random MAC (পর্ব ১২)। fd00::…/64 scope global dynamic ঠিকানাটি SLAAC দিয়ে এসেছে: valid_lft 86400sec preferred_lft 14400sec হলো RA-তে পাওয়া prefix-এর আয়ু, আর mngtmpaddr মানে চাইলে kernel এই prefix থেকে temporary ঠিকানাও বানাত (use_tempaddr=0, তাই বানায়নি)। Prefix fd00::/64 একটি ULA. Route তালিকায় default via fe80::2 … proto ra … expires 1799sec: default router-এর ঠিকানা link-local, এসেছে RA থেকে, আর তার আয়ু প্রায় ১৮০০ সেকেন্ড — simulator-এর “router life 1800 s”-এর সাথে মিল। /proc/net/if_inet6-এর কলামগুলো: ৩২ hex অঙ্কে পুরো ঠিকানা, interface নম্বর, prefix দৈর্ঘ্য hex-এ (40 = ৬৪, 80 = ১২৮), scope (00 global, 20 link, 10 host) আর flags — 0x80 মানে permanent (আয়ু নেই), SLAAC-এর ঠিকানায় 0x00, কারণ তার আয়ু আছে। শেষে addr_gen_mode=0 মানে Linux এখানে EUI-64 দিয়ে ID বানায় (২ হলে stable privacy, ৩ হলে random). all আর default-এর mtu=1280 kernel-এর শুরুর মান — IPv6-এর ন্যূনতম MTU; আসল interface নিজের MTU পায় (tap0-এ 65520). Windows-এ একই তথ্য দেখায় PowerShell-এর Get-NetIPAddress -AddressFamily IPv6.

আরও গভীরে: Linux-এর neighbour cache (ip -6 neigh) প্রতিটি প্রতিবেশীর একটি অবস্থা রাখে — INCOMPLETE (NS গেছে, উত্তর আসেনি), REACHABLE (সম্প্রতি নিশ্চিত), STALE (পুরোনো, পরের packet-এ যাচাই), DELAY আর PROBE — এগুলো RFC 4861-এর Neighbor Unreachability Detection-এর রাষ্ট্রযন্ত্র। DAD-এর প্রায় ১ সেকেন্ড দেরি কমাতে RFC 4429-এর “optimistic DAD” আছে, যেখানে ঠিকানাটি সাবধানে আগেই ব্যবহার শুরু হয়। Kernel RA গ্রহণ করবে কি না তা ঠিক করে accept_ra, আর interface-টি নিজেই packet forward করলে (router মোড) সাধারণত RA গ্রহণ বন্ধ থাকে — container আর VM-এর host-এ IPv6 হঠাৎ “হারিয়ে যাওয়ার” একটি পরিচিত কারণ এটি।

৮ · IPv4 থেকে IPv6 — dual stack, tunnel আর অনুবাদ

পুরো ইন্টারনেট এক রাতে বদলানো অসম্ভব, তাই বহু বছর ধরে দুই protocol পাশাপাশি চলবে। সহাবস্থানের তিনটি মূল কৌশল:

📱 Dual stack

যন্ত্র আর router-এ IPv4 আর IPv6 দুটিই একসাথে চালু — যেমন dual-SIM ফোনে দুটি নম্বর। গন্তব্যের যেটি আছে, সেটি দিয়ে কথা। সবচেয়ে সরল আর প্রচলিত পথ, কিন্তু দুটো নেটওয়ার্ক চালানোর খরচও দ্বিগুণ, আর IPv4 ঠিকানার অভাব মেটে না।

dual stack

📦 Tunnel

IPv6 packet-কে IPv4 packet-এর ভেতরে খামে ভরে IPv4-এর পথ পার করা — কুরিয়ারের বড় প্যাকেটের ভেতরে আরেকটি খাম। 6in4-এ IPv4 header-এর Protocol ঘরে ৪১ বসে।

tunnel

🗣️ অনুবাদ (translation)

শুধু-IPv6 নেটওয়ার্কের যন্ত্রকে IPv4 সার্ভারের সাথে কথা বলাতে মাঝখানে একজন দোভাষী — header বদলে দেয়। NAT64, DNS64, 464XLAT.

NAT64

Tunnel-এর ইতিহাস — যা এখন প্রায় অতীত

6to4 (RFC 3056) একটি public IPv4 ঠিকানা থেকে 2002::/16-এর একটি prefix বানাত; কিন্তু সর্বজনীন relay-গুলো অনির্ভরযোগ্য হওয়ায় সমস্যা বাড়ে, আর ২০১৫ সালে RFC 7526 এর relay ব্যবস্থাকে অপ্রচলিত ঘোষণা করে। Teredo (RFC 4380) NAT-এর পেছন থেকে UDP-র ভেতরে IPv6 নিত; Windows-এ বহু বছর ছিল, পরে ধীরে ধীরে বাদ পড়েছে বলে জানা যায়। আজ tunnel মূলত হাতে কনফিগার করা 6in4 (RFC 4213) বা tunnel broker-এর সেবা, আর ISP-র ভেতরে 6rd-এর মতো কৌশল। নিরাপত্তার দিক: tunnel-এর ভেতরের IPv6 শুধু-IPv4 firewall-এর চোখ এড়াতে পারে, তাই সীমানায় অপ্রত্যাশিত tunnel নজরে রাখা হয়।

NAT64 আর DNS64 — শুধু-IPv6 মোবাইল নেটওয়ার্কের রহস্য

অনেক বড় মোবাইল অপারেটর এখন ফোনকে শুধু IPv6 ঠিকানা দেয় — লাখ লাখ গ্রাহকের জন্য IPv4 ঠিকানা আর নেই। তাহলে শুধু-IPv4 একটি ওয়েবসাইট খোলে কীভাবে? দুই সহকারী মিলে:

  1. DNS64: ফোন নামের IPv6 ঠিকানা (AAAA record, পর্ব ৩৫) চাইল। সাইটের আছে শুধু IPv4 (ধরুন 192.0.2.33). DNS64 তখন একটি “বানানো” IPv6 ঠিকানা ফেরত দেয়: well-known prefix 64:ff9b::/96-এর পেছনে IPv4-এর ৩২ বিট — 64:ff9b::c000:221 (লেখা যায় 64:ff9b::192.0.2.33).
  2. NAT64: ফোন সেই ঠিকানায় packet পাঠায়। অপারেটরের NAT64 যন্ত্র prefix দেখে চেনে, শেষ ৩২ বিট থেকে IPv4 গন্তব্য বের করে, নিজের IPv4 ঠিকানা দিয়ে header অনুবাদ করে পাঠায় — উত্তর ফেরার পথে উল্টো অনুবাদ (NAT-এর টেবিলের মতো, পর্ব ১৯)।

সমস্যা থাকে সেই অ্যাপের, যেগুলো DNS ছাড়াই সরাসরি IPv4 ঠিকানা লেখে (কিছু পুরোনো গেম, VoIP). তাদের জন্য 464XLAT (RFC 6877): ফোনের ভেতরে একটি ছোট অনুবাদক (CLAT) অ্যাপকে একটি নকল IPv4 ঠিকানা দেয়, IPv4 packet-কে IPv6-এ অনুবাদ করে পাঠায়, আর অপারেটরের NAT64 আবার IPv4-এ ফেরায় — ৪ → ৬ → ৪. অনেক মোবাইল নেটওয়ার্কে এই সমাধান প্রচলিত বলে জানা যায়, আর Android-এ CLAT অন্তর্ভুক্ত আছে।

Happy Eyeballs — দুই পথে একসাথে চেষ্টা

Dual stack-এর একটি পুরোনো বিড়ম্বনা: সাইটের AAAA record আছে, কিন্তু কোথাও IPv6 পথ ভাঙা। ব্রাউজার আগে IPv6 চেষ্টা করে timeout-এর জন্য অনেক সেকেন্ড বসে থাকলে ব্যবহারকারী ভাবেন “ইন্টারনেট ধীর”। Happy Eyeballs (RFC 6555, পরে RFC 8305) সমাধান দেয়: প্রথমে IPv6 দিয়ে চেষ্টা, কিন্তু খুব অল্প সময়ে (RFC 8305 ২৫০ মিলিসেকেন্ড সুপারিশ করে) উত্তর না এলে সমান্তরালে IPv4-এর চেষ্টাও শুরু — যেটি আগে জোড়া লাগে, সেটিই থাকে। ঢাকার দুটি বাস রুটের মতো: পছন্দের রুটের বাস এক মুহূর্তে না এলে অন্য রুটের বাসেও হাত তোলা। আধুনিক ব্রাউজার আর OS-এ এটি ভেতরে ভেতরে চালু থাকে।

৯ · নিরাপত্তা — NAT নেই, firewall আছে

IPv4-এর যুগে অনেকেই ধরে নিয়েছিলেন NAT-ই নিরাপত্তা, কারণ বাইরে থেকে ভেতরের যন্ত্রে সরাসরি সংযোগ শুরু করা যেত না। IPv6-এ প্রতিটি যন্ত্রের global ঠিকানা আছে, তাই সেই “অঘোষিত দেয়াল” নেই। প্রকৃত সুরক্ষা সবসময় এসেছে stateful firewall থেকে: ভেতর থেকে শুরু হওয়া সংযোগের উত্তর আসতে দেওয়া, আর বাইরে থেকে শুরু হওয়া নতুন সংযোগ ডিফল্টভাবে আটকানো। বাসার router-এর জন্য RFC 6092 ঠিক এটাই সুপারিশ করে। কয়েকটি প্রতিরক্ষার নিয়ম:

  • Firewall-এ IPv6 নিয়ম আলাদা করে দেখুন: শুধু IPv4-এর নিয়ম লিখে IPv6-কে খোলা রাখা একটি পরিচিত ভুল — অনেক OS-এ IPv6 ডিফল্টভাবে চালু থাকে, আপনি ব্যবহার না করলেও। Linux-এ nftables-এর inet family দুটিকে একসাথে ধরে (পর্ব ৪৯)।
  • ICMPv6 পুরোপুরি বন্ধ নয়: NDP আর Packet Too Big ছাড়া IPv6 চলে না (অংশ ৬); RFC 4890-এর তালিকা মেনে বেছে বেছে সীমিত করুন।
  • RA Guard: একই LAN-এর কোনো যন্ত্র ভুলে (ধরুন কেউ Windows-এ internet sharing চালু করলেন) বা উদ্দেশ্যমূলকভাবে নিজেকে router ঘোষণা করলে সবার traffic তার দিকে যেতে পারে। Managed switch-এ RA Guard (RFC 6105) শুধু router-এর port থেকে RA আসতে দেয় — IPv4-এর DHCP snooping-এর সমতুল্য।
  • বড় subnet, বড় neighbour cache: একটি /64-এ ২৬৪ ঠিকানা; বাইরে থেকে কেউ অস্তিত্বহীন অসংখ্য ঠিকানায় packet পাঠালে router প্রতিটির জন্য NS পাঠিয়ে cache ভরে ফেলতে পারে। প্রতিরক্ষা: router-এ NDP rate limit আর cache-এর সীমা।
  • গোপনীয়তা: Client যন্ত্রে temporary বা stable privacy ঠিকানা রাখুন (অংশ ৫); সার্ভারে সহজে চেনা স্থির ঠিকানা স্বাভাবিক। Temporary ঠিকানা বদলায় বলে log তদন্তে /64 ধরে খোঁজা প্রায়ই কার্যকর।
মূল ধারণা

২৬৪ ঠিকানার subnet-এ অন্ধভাবে যন্ত্র খুঁজে পাওয়া কঠিন, কিন্তু সেটি নিরাপত্তা-ব্যবস্থা নয় — DNS, log আর অনুমানযোগ্য ঠিকানা (::1, EUI-64) দিয়ে যন্ত্র খুঁজে পাওয়া যায়। নিরাপত্তা আসে firewall নীতি, হালনাগাদ software আর LAN-এর প্রতিরক্ষা (RA Guard, port security) থেকে। আক্রমণ আর প্রতিরক্ষার বিস্তারিত পর্ব ৫০-এ।

১০ · AI-এর যুগে IPv6

IPv6-এর ধারণা ব্যাখ্যায় AI ভালো, কিন্তু ঠিকানা ছোট করা, EUI-64-এর বিট আর ঠিকানার ধরনে সে আত্মবিশ্বাসের সাথে ভুল করে, আর সমস্যায় প্রায়ই “IPv6 বন্ধ করে দিন” বলে কারণটাই লুকিয়ে ফেলে। পরিচিত ভুলগুলো:

AI-এর ভুলউদাহরণকীভাবে যাচাই করবেন
ভুল compressionদুটি ::, একটি শূন্য-ঘরকে ::, ডানের শূন্য বাদঅংশ ২-এর টুল বা inet_ntop/Python-এর ipaddress মডিউলে মিলিয়ে নিন
IPv4-এর ধারণা চাপানো“IPv6-এ broadcast ঠিকানা”, “IPv6 ARP”, “/120 দিয়ে LAN”Broadcast নেই, NDP আছে; SLAAC-এর LAN /64
EUI-64-এর বিটU/L বিট না উল্টানো, ff:fe ভুল জায়গায়Stepper-এর ধাপ ধরে binary-তে নিজে করুন
পুরোনো কমান্ডifconfig inet6, netstat -6, ping6 একমাত্র উপায় বলাআধুনিক Linux-এ ip -6 addr, ip -6 route, ip -6 neigh, ss; man page দেখুন
বিপজ্জনক পরামর্শ“সব ICMPv6 বন্ধ”, “IPv6 বন্ধ করলেই নিরাপদ”, “firewall খুলে দিন”RFC 4890 আর আপনার firewall-এর ডকুমেন্টেশন; ল্যাবে পরীক্ষা
বানানো সংখ্যা ও RFCদেশের IPv6 ব্যবহারের শতাংশ, ভুল RFC নম্বরMeasurement সাইট দেখুন; rfc-editor.org-এ নম্বর আর শিরোনাম মেলান
“আসল-দেখতে” ঠিকানাউদাহরণে কোনো বাস্তব প্রতিষ্ঠানের prefixডকুমেন্টেশনে শুধু 2001:db8::/32 ব্যবহার করুন

IPv6-এর হিসাব বা পরিকল্পনা AI-কে দিয়ে করালে ধাপ দেখাতে আর যাচাইয়ের উপায় বলতে বলুন:

আমি IPv6 শিখছি। আমাদের প্রতিষ্ঠান 2001:db8:acad::/48 পেয়েছে (ডকুমেন্টেশন prefix, উদাহরণের জন্য)। তিনটি সাইট, প্রতিটিতে কর্মী, অতিথি আর সার্ভার LAN. ১. ১৬ বিটের subnet ID কীভাবে nibble ধরে সাজাবে, একটি টেবিলে দাও — প্রতিটি LAN /64. ২. প্রতিটি সাইটের aggregate prefix কত হবে (/52 বা /56) আর কেন, দেখাও। ৩. MAC 00:00:5e:00:53:2c থেকে modified EUI-64 interface ID, link-local ঠিকানা আর solicited-node ঠিকানা ধাপে ধাপে binary-সহ বের করো। ৪. সব ঠিকানা RFC 5952-এর canonical রূপে লেখো। ৫. কোনো কমান্ড দিলে কোন OS-এর, তা বলো; Linux-এ ip কমান্ড ব্যবহার করো। শেষে বলো, আমি কোন টুল বা পরীক্ষা দিয়ে তোমার প্রতিটি উত্তর যাচাই করতে পারি।

AI-এর দেওয়া IPv6-উত্তর মানার আগে — চেকলিস্ট

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

  • IPv6 ঠিকানা কত বিটের, আর 2001:0db8:0000:0000:0000:0000:0002:0001-এর সংক্ষিপ্ত রূপ কী? — ১২৮ বিট; 2001:db8::2:1.
  • IPv4 আর IPv6 header-এর তিনটি পার্থক্য বলুন। — IPv6 header নির্দিষ্ট ৪০ বাইট; checksum নেই; router fragmentation নেই (শুধু উৎস, extension header দিয়ে); options extension header-এ; TTL-এর নাম Hop Limit.
  • IPv6-এ ARP-এর কাজ কে করে? — ICMPv6 Neighbor Discovery-র Neighbor Solicitation আর Advertisement, solicited-node multicast দিয়ে।
  • SLAAC কী, আর RA-র M ও O পতাকার মানে কী? — Router-এর ঘোষিত prefix আর নিজের interface ID মিলিয়ে host নিজে ঠিকানা বানায়; M=1 ঠিকানা DHCPv6 থেকে, O=1 শুধু অন্যান্য তথ্য DHCPv6 থেকে।
  • IPv6-এ broadcast নেই কেন, আর তার জায়গায় কী? — Broadcast সব যন্ত্রকে বিরক্ত করে; তার বদলে multicast — ff02::1 সবার জন্য, আর লক্ষ্যভিত্তিক solicited-node দল।

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

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলোই আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।

প্র ০১IPv6-এর স্পেসিফিকেশন ১৯৯৫ সালে এসেছে, অথচ তিন দশক পরেও IPv4 চলছে। এত ধীর কেন — প্রযুক্তি না অর্থনীতি?

মূলত অর্থনীতি আর “কে আগে” সমস্যা। IPv6 IPv4-এর সাথে পশ্চাৎ-সামঞ্জস্যপূর্ণ নয় — একটি শুধু-IPv6 যন্ত্র একটি শুধু-IPv4 সার্ভারের সাথে মাঝখানে অনুবাদক ছাড়া কথাই বলতে পারে না। তাই কোনো একটি পক্ষ একা IPv6-এ গিয়ে লাভ পায় না: ওয়েবসাইট ভাবে “গ্রাহকরা তো IPv6-এ নেই”, ISP ভাবে “সাইটগুলো তো IPv6-এ নেই”, আর যন্ত্র-নির্মাতা ভাবেন “নেটওয়ার্কে তো নেই” — ক্লাসিক মুরগি-আর-ডিম।

অন্যদিকে IPv4-এর অভাবের ব্যথা কমিয়ে দিয়েছে NAT. ১৯৯০-এর দশকের মাঝামাঝি থেকে বাসা আর অফিসে NAT সাধারণ হলো, পরে ISP-রা পুরো এলাকার গ্রাহককে একটি ঠিকানার পেছনে রাখতে CGNAT বসাল। NAT-এর দাম আছে — log রাখা জটিল, peer-to-peer অ্যাপ কঠিন, একজনের অপব্যবহারে একই ঠিকানার সবাই ব্লক হতে পারেন — কিন্তু দাম ছড়িয়ে থাকে বলে চোখে পড়ে কম। ২০১১ সালে IANA-র ভান্ডার শেষ হওয়ার পর IPv4 ঠিকানার একটি বাজার তৈরি হলো, যেখানে ঠিকানা কেনাবেচা হয়; দাম বাড়তে থাকায় IPv6-এর পক্ষে যুক্তি জোরালো হচ্ছে।

যেখানে একটি প্রতিষ্ঠান নিজে পুরো শিকল নিয়ন্ত্রণ করে, সেখানে পরিবর্তন দ্রুত হয়েছে। বড় মোবাইল অপারেটর ফোন, নেটওয়ার্ক আর NAT64 — তিনটিই নিয়ন্ত্রণ করে; লাখ লাখ নতুন গ্রাহকের জন্য IPv4 জোগাড় করার চেয়ে শুধু-IPv6 অনেক সস্তা। বড় কনটেন্ট প্রতিষ্ঠান আর CDN-ও আগেভাগে IPv6 চালু করেছে — ২০১২ সালের ৬ জুন “World IPv6 Launch”-এ বহু বড় সাইট আর ISP একসাথে স্থায়ীভাবে IPv6 চালু করেছিল। অন্যদিকে ছোট প্রতিষ্ঠান, পুরোনো এন্টারপ্রাইজ software আর প্রশিক্ষণের অভাব ধীরগতির কারণ। অগ্রগতি দেশভেদে খুব আলাদা, তাই বর্তমান অবস্থা Google, APNIC Labs বা Cloudflare Radar-এর পরিসংখ্যানে নিজে দেখে নেওয়াই ঠিক।

মূল উপলব্ধি: নেটওয়ার্কের “সরু কোমর” — IP — বদলানো সবচেয়ে কঠিন, কারণ সবাইকে একসাথে বদলাতে হয়। প্রযুক্তি তৈরি থাকলেও গ্রহণ নির্ভর করে খরচ, প্রণোদনা আর কে পুরো শিকল নিয়ন্ত্রণ করে তার ওপর।

প্র ০২প্রতিটি LAN-এ ২৬৪ ঠিকানা — যেখানে বাস্তবে কয়েকশো যন্ত্র থাকে। এটা কি ভয়াবহ অপচয় নয়? /64 কেন?

IPv4-এর চোখে দেখলে অপচয় মনে হয়, কারণ সেখানে প্রতিটি ঠিকানা দামি। IPv6-এর নকশায় চিন্তাটি উল্টো: ঠিকানা সস্তা, ব্যবস্থাপনা দামি। ৬৪ বিটের interface ID রাখার কয়েকটি কারণ:

  • নিজে নিজে অনন্য ঠিকানা: MAC ৪৮ বিট (বা পরে ৬৪ বিটের EUI-64). পুরো ID ধরে রাখতে ৬৪ বিট লাগত। আজ random ID-ও ৬৪ বিটের বিশাল জায়গায় বেছে নেওয়া হয়, তাই সংঘাতের সম্ভাবনা কার্যত শূন্য — DAD প্রায় কখনো ব্যর্থ হয় না।
  • Subnet-এর মাপ নিয়ে আর মাথাব্যথা নেই: IPv4-এ প্রতিটি LAN-এর জন্য “কয়টি host” হিসাব করে /26 না /27 — এই প্রশ্নে অনেক ভুল হয়, পরে যন্ত্র বাড়লে renumbering. IPv6-এ সব LAN /64, কখনো ভরবে না।
  • গোপনীয়তা: Temporary আর stable privacy ঠিকানা কাজ করে কারণ ৬৪ বিটের জায়গায় random মান অনুমান করা যায় না।
  • সরল hardware: অনেক router সামনের ৬৪ বিটের ওপর দ্রুত lookup অপ্টিমাইজ করে।

তবে মোট পরিমাণটাও দেখুন। সামনের ৬৪ বিট দিয়েই ২৬৪টি /64 নেটওয়ার্ক — পৃথিবীর প্রতিটি মানুষকে কয়েকশো কোটি LAN দেওয়া যায়, আর global unicast এখনো মোট জায়গার মাত্র এক-অষ্টমাংশ (2000::/3). ভবিষ্যতের প্রয়োজনে বাকি অংশ সংরক্ষিত।

এর বিরুদ্ধ যুক্তিও আছে, আর IETF তা আলোচনা করেছে (RFC 7421 “64-bit boundary”-র সুবিধা-অসুবিধা বিশ্লেষণ করে)। বিশাল subnet neighbour cache ভরিয়ে দেওয়ার আক্রমণের ঝুঁকি বাড়ায় (অংশ ৯), আর point-to-point link-এ /64-এর বদলে /127 ব্যবহারই এখন সুপারিশ (RFC 6164). কিন্তু যেখানে host আছে, সেখানে /64-ই নিয়ম — না মানলে SLAAC আর অনেক OS-এর আচরণ ভেঙে যায়।

মূল উপলব্ধি: “অপচয়” আর “কার্যকারিতা” প্রেক্ষিতনির্ভর। যে সম্পদ প্রায় অফুরন্ত, সেটি খরচ করে যদি মানুষের সময় আর ভুল কমে, তবে সেটিই ভালো প্রকৌশল।

প্র ০৩EUI-64 এত সুন্দর বুদ্ধি ছিল — MAC থেকে নিশ্চিত অনন্য ঠিকানা। তাহলে এখন সবাই তা থেকে সরে যাচ্ছে কেন?

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

ল্যাপটপ আর স্মার্টফোনের যুগে সমস্যা স্পষ্ট হলো। আপনার ফোন বাসার Wi-Fi, অফিস, বিশ্ববিদ্যালয়, মোবাইল ডেটা — সব জায়গায় একই interface ID নিয়ে যায়। ফলে কোনো ওয়েবসাইট বা বিজ্ঞাপন-ট্র্যাকার cookie ছাড়াই, শুধু ঠিকানার শেষ ৬৪ বিট দেখে বুঝতে পারে “এই সেই যন্ত্র”, এমনকি আপনার চলাফেরার একটি ছবিও বানাতে পারে। আরও আছে: OUI দেখে নির্মাতা জানা যায়, আর অনুমানযোগ্য ID থাকলে নির্দিষ্ট ধরনের যন্ত্র খোঁজা সহজ হয়।

সমাধান ধাপে ধাপে এসেছে। ২০০১ সালে RFC 3041, পরে RFC 4941 (২০০৭) আর ২০২১ সালে RFC 8981 temporary address আনে: random ID, নিয়মিত বদলায়, বাইরের সংযোগে ব্যবহার হয়। কিন্তু শুধু temporary ঠিকানা থাকলে নিজের নেটওয়ার্কে firewall নিয়ম বা log বিশ্লেষণ কঠিন হয়। তাই ২০১৪ সালে RFC 7217 stable privacy আনে: hash(prefix, interface, গোপন চাবি) — একই নেটওয়ার্কে স্থির, নেটওয়ার্ক বদলালে সম্পূর্ণ আলাদা। ২০১৭ সালে RFC 8064 স্পষ্টভাবে সুপারিশ করে: স্থির ঠিকানার ডিফল্ট হবে RFC 7217, EUI-64 নয়। একই সময়ে ফোনগুলো Wi-Fi-তে random MAC ব্যবহার শুরু করল (পর্ব ১২) — ফলে EUI-64 চালু থাকলেও ID আর কারখানার MAC থেকে আসে না।

দাম কী দিতে হলো? নেটওয়ার্ক প্রশাসকের কাজ কঠিন হলো — একটি যন্ত্রের অনেক ঠিকানা, সেগুলো বদলায়, তাই “এই ঠিকানা কার” জানতে router-এর neighbour table বা switch-এর তথ্য মেলাতে হয়। কিছু প্রতিষ্ঠান তাই নিজের নেটওয়ার্কে stateful DHCPv6 বা কঠোর নীতি ব্যবহার করে।

মূল উপলব্ধি: একটি protocol-এর নকশা তার সময়ের অনুমানের ওপর দাঁড়ায়। ব্যবহার বদলালে — স্থির কম্পিউটার থেকে পকেটের ফোন — একই বৈশিষ্ট্য সুবিধা থেকে ঝুঁকিতে পরিণত হয়, আর তখন মানও বদলাতে হয়।

প্র ০৪IPv6 header থেকে checksum বাদ, router-এর fragmentation বাদ — এটা কি সাহসী সরলীকরণ, নাকি নতুন ঝুঁকি?

দুটোই। সিদ্ধান্তগুলোর পেছনে end-to-end চিন্তা: যে কাজ প্রান্তে ভালোভাবে করা যায়, তা পথের প্রতিটি router-এ বারবার করার দরকার নেই।

Checksum: IPv4 header checksum শুধু header পাহারা দেয়, আর TTL প্রতি hop-এ বদলায় বলে প্রতিটি router-কে তা নতুন করে হিসাব করতে হয় — কোটি কোটি packet-এ এটি খরচ। অথচ প্রায় প্রতিটি link-এর নিজের শক্তিশালী CRC আছে (পর্ব ৯), আর TCP/UDP checksum-এ উৎস ও গন্তব্য ঠিকানাসহ একটি “pseudo-header” থাকে — ঠিকানা নষ্ট হলে transport স্তরে ধরা পড়ে। তাই IPv6-এ UDP checksum প্রায় সব ক্ষেত্রে বাধ্যতামূলক করা হয়েছে। ঝুঁকি: router-এর মেমরিতে নষ্ট হওয়া header CRC ধরবে না, কারণ CRC প্রতিটি link-এ নতুন করে হিসাব হয় — তবে transport checksum শেষে ধরে।

Fragmentation: IPv4-এ পথের router packet ভাঙলে সেই router-এর CPU খাটে, আর একটি টুকরো হারালে পুরো packet আবার পাঠাতে হয়। IPv6-এ ভাঙার দায় উৎসের, আর উৎস জানে PMTUD দিয়ে। এখানে আসল ঝুঁকি: PMTUD নির্ভর করে ICMPv6 Packet Too Big-এর ওপর, আর বহু firewall ICMP আটকায় — ফলে “black hole”: ছোট packet যায়, বড়গুলো নিঃশব্দে হারায়। এর প্রতিকার হিসেবে এসেছে TCP-র MSS সমন্বয় আর Packetization Layer PMTUD (যেখানে transport নিজে ছোট-বড় packet পাঠিয়ে মাপ বোঝে)। Fragment header নিয়েও নিরাপত্তা সমস্যা হয়েছে — টুকরোর ভেতরে লুকিয়ে firewall ফাঁকি দেওয়া — তাই পরের RFC-গুলো নিয়ম কড়া করেছে, যেমন প্রথম টুকরোতেই পুরো header-শিকল থাকা বাধ্যতামূলক (RFC 7112).

Extension header-এর নমনীয়তাও একই গল্প: কাগজে সুন্দর, বাস্তবে অনেক middlebox অচেনা header ফেলে দেয়। তাই QUIC-এর মতো আধুনিক protocol (পর্ব ৩৩) নতুন বৈশিষ্ট্য IP স্তরে না রেখে UDP-র ভেতরে, encrypted অবস্থায় রাখে।

মূল উপলব্ধি: সরলীকরণ কাজ সরায় না, দায়িত্ব স্থানান্তর করে। নকশা সফল হয় তখনই, যখন নতুন দায়িত্ব নেওয়া পক্ষ — এখানে প্রান্তের host আর ICMPv6-কে চলতে দেওয়া firewall — সত্যিই তা পালন করে।

প্র ০৫IPv6-এ NAT নেই বলে কেউ কেউ ভয় পান — “প্রতিটি যন্ত্র ইন্টারনেটে খোলা।” এই ভয় কতটা সঠিক, আর সঠিক নকশা কী?

ভয়টি একটি ভুল ধারণা থেকে আসে: NAT-কে firewall ভাবা। NAT-এর উদ্দেশ্য ঠিকানা বাঁচানো; বাইরে থেকে নতুন সংযোগ আটকানোটা তার পার্শ্বফল, কারণ router জানে না সেই packet ভেতরের কোন যন্ত্রে যাবে। এই আচরণটুকুই আসলে একটি stateful firewall-এর মূল নিয়ম — “ভেতর থেকে শুরু হওয়া সংযোগের উত্তর ঢুকতে দেওয়া, বাকি নতুন সংযোগ আটকানো”। IPv6-এ ঠিক এই নিয়মটি firewall-এ লিখলেই সমান সুরক্ষা মেলে, সাথে NAT-এর জটিলতা থাকে না। বাসার router-এর জন্য RFC 6092 এমন ডিফল্ট আচরণই সুপারিশ করে, আর বেশিরভাগ আধুনিক বাসার router IPv6-এ বাইরের নতুন সংযোগ ডিফল্টভাবে আটকায় বলে জানা যায় — তবু নিজের router-এর সেটিং দেখে নিন।

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

IPv6-এ সঠিক নকশার উপাদান: সীমানায় stateful firewall, ডিফল্ট-অস্বীকার নীতি; ICMPv6-এর দরকারি বার্তা খোলা (RFC 4890); LAN-এ RA Guard আর DHCPv6 Guard; client-এ privacy ঠিকানা; সার্ভারের ঠিকানা আর খোলা port-এর হালনাগাদ তালিকা; আর IPv4 ও IPv6-এর নিয়ম একসাথে পর্যালোচনা — সবচেয়ে বেশি ঘটনা ঘটে যেখানে কেউ IPv6 চালু আছে বলেই জানতেন না। একটি বড় সুবিধাও আছে: প্রতিটি যন্ত্রের নিজস্ব ঠিকানা থাকায় log-এ কে কী করেছে তা স্পষ্ট।

মূল উপলব্ধি: নিরাপত্তা ঠিকানার ধরনে নয়, নীতিতে। NAT হারানো মানে সুরক্ষা হারানো নয় — যদি আপনি সচেতনভাবে firewall নীতি লেখেন আর IPv6-কে IPv4-এর মতোই সমান মনোযোগ দেন।

অনুশীলন

খাতা-কলম নিয়ে বসুন — আগে নিজে করুন, তারপর উত্তর মেলান।

  1. হাতে হিসাব (EUI-64): একটি interface-এর MAC 00:00:5e:00:53:2c. Router ঘোষণা করছে 2001:db8:acad:20::/64. বের করুন — (ক) modified EUI-64 interface ID, (খ) link-local ঠিকানা, (গ) global ঠিকানা, (ঘ) solicited-node ঠিকানা আর তার Ethernet MAC.

    মাঝে ff:fe: 00:00:5e:ff:fe:00:53:2c. প্রথম বাইট 00 = 0000 0000, bit 1 উল্টে 02. তাই:

    • (ক) interface ID 0200:5eff:fe00:532c → 200:5eff:fe00:532c
    • (খ) fe80::200:5eff:fe00:532c
    • (গ) 2001:db8:acad:20:200:5eff:fe00:532c
    • (ঘ) শেষ ২৪ বিট 00:53:2c → ff02::1:ff00:532c; MAC 33:33:ff:00:53:2c
  2. Subnet পরিকল্পনা (numerical): একটি প্রতিষ্ঠান 2001:db8:acad::/48 পেয়েছে। (ক) এতে কতটি /64 আর কতটি /56? (খ) subnet ID-কে ০ থেকে গুনলে ৩০০ নম্বর /64-টির prefix কী? (গ) 2001:db8:acad:4a7::/64 কোন /56-এর ভেতরে?

    (ক) /48 থেকে /64: ১৬ বিট → ২১৬ = ৬৫,৫৩৬টি। /56: ৮ বিট → ২৮ = ২৫৬টি (প্রতিটিতে আবার ২৫৬টি /64).

    (খ) ৩০০ = ২৫৬ + ৪৪ = hex 0x12c (১×২৫৬ + ২×১৬ + ১২)। subnet ID 012c → 2001:db8:acad:12c::/64.

    (গ) /56 মানে subnet ID-এর প্রথম ৮ বিট (প্রথম দুই hex অঙ্ক) স্থির। 04a7-এর প্রথম দুই অঙ্ক 04, বাকি দুটি শূন্য করলে 0400 → 2001:db8:acad:400::/56 (এতে আছে …:400 থেকে …:4ff).

  3. আউটপুট আন্দাজ করুন: C-এর inet_pton আর তারপর inet_ntop নিচের প্রতিটি লেখার জন্য কী ছাপবে? (ক) 2001:db8:0:0:1:0:0:0 (খ) 2001:db8:0:0:0:0:2:1 (গ) 2001:DB8:0:1:0:0:0:1 (ঘ) 2001:db8:::1

    (ক) শূন্য-সারি: ঘর ৩–৪ (২টি) আর ঘর ৬–৮ (৩টি) — লম্বাটি জেতে: 2001:db8:0:0:1::. (খ) একটিই সারি, ঘর ৩–৬: 2001:db8::2:1. (গ) ছোট হাতের অক্ষর, ঘর ৫–৭: 2001:db8:0:1::1. (ঘ) ::: কোনো বৈধ লেখা নয় — inet_pton 0 ফেরত দেবে, তাই অংশ ২-এর প্রোগ্রামের মতো “invalid” ছাপা হবে। নিজে যাচাই করতে অংশ ২-এর C প্রোগ্রামের তালিকায় এগুলো বসিয়ে চালান।

  4. কমান্ড লিখুন: একটি Linux যন্ত্রে (ক) শুধু eth0-এর IPv6 ঠিকানা, (খ) IPv6 routing table, (গ) IPv6 প্রতিবেশীদের তালিকা (neighbour cache) দেখার কমান্ড লিখুন। Windows-এ ঠিকানা দেখার একটি কমান্ডও বলুন। কোন আউটপুট দেখে বুঝবেন ঠিকানাটি SLAAC-এ এসেছে?

    (ক) ip -6 addr show dev eth0 (খ) ip -6 route (গ) ip -6 neigh. Windows-এ netsh interface ipv6 show addresses বা PowerShell-এ Get-NetIPAddress -AddressFamily IPv6.

    SLAAC-এর চিহ্ন: Linux-এ ঠিকানার সাথে dynamic আর সসীম valid_lft/preferred_lft (অংশ ৭-এর আউটপুটের মতো), route-এ proto ra; temporary হলে temporary লেখা থাকে। Windows-এর Get-NetIPAddress-এ PrefixOrigin “RouterAdvertisement” দেখায়। পুরোনো ifconfig অনেক নতুন distribution-এ ডিফল্টভাবে থাকেই না।

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

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

ক্রমএকটি IPv6 host চালু হওয়া থেকে global ঠিকানা পাওয়া পর্যন্ত (SLAAC) ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Interface ID বানিয়ে tentative link-local ঠিকানা তৈরি
  2. DAD — উৎস :: দিয়ে solicited-node দলে Neighbor Solicitation
  3. ff02::2-এ Router Solicitation
  4. Router-এর Router Advertisement — prefix, A পতাকা, router lifetime
  5. Prefix + interface ID দিয়ে global ঠিকানা, আবার DAD

2001:0db8:0000:0000:0000:0000:0002:0001 ঠিকানার RFC 5952 canonical রূপ কোনটি?

  • 2001:db8:0::2:1
  • 2001:db8::2:1
  • 2001:db8::::2:1
  • 2001:db8::0002:0001

একটি interface-এর MAC 00:00:5e:00:53:2c. Modified EUI-64 পদ্ধতিতে তার interface ID কোনটি?

  • 0:5eff:fe00:532c
  • 200:5e00:53ff:fe2c
  • 200:5eff:fe00:532c
  • 0:5eff:ff00:532c

IPv6-এ একটি host একই LAN-এর 2001:db8::2:abcd:1234 ঠিকানার MAC জানতে চায়। Neighbor Solicitation কোন ঠিকানায় যাবে?

  • ff02::1:ffcd:1234
  • ff02::1
  • ff02::1:abcd:1234
  • ff02::2

একটি IPv6 router এমন একটি packet পেল, যা পরের link-এর MTU-র চেয়ে বড়। Router কী করবে?

  • Packet-টি টুকরো করে পাঠাবে
  • DF পতাকা দেখে সিদ্ধান্ত নেবে
  • শেষের অংশ কেটে পাঠাবে
  • ফেলে দিয়ে উৎসকে ICMPv6 Packet Too Big পাঠাবে

একটি Router Advertisement-এ M=0 আর O=1. একটি সাধারণ host কী করবে?

  • ঠিকানা আর DNS — দুটোই DHCPv6 থেকে নেবে
  • ঠিকানা SLAAC দিয়ে বানাবে, DNS-এর মতো তথ্য DHCPv6 থেকে নেবে
  • শুধু default router-এর জন্য DHCPv6 ব্যবহার করবে
  • কিছুই কনফিগার করবে না, শুধু link-local রাখবে

IPv4 header-এর তুলনায় IPv6 header সম্পর্কে কোন কথাটি সঠিক?

  • IPv6 header-এর মাপ ৪০ থেকে ৮০ বাইটের মধ্যে বদলায়
  • IPv6 header checksum প্রতিটি router নতুন করে হিসাব করে
  • IPv6 header নির্দিষ্ট ৪০ বাইট, checksum নেই, আর TTL-এর জায়গায় Hop Limit
  • Payload Length ঘরে header-সহ পুরো packet-এর মাপ থাকে

শব্দকোষ

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

মনে রাখুন

  1. IPv6 ঠিকানা ১২৮ বিট, ৮টি hex ঘর; canonical রূপ: শুরুর শূন্য বাদ, সবচেয়ে লম্বা (সমান হলে প্রথম) শূন্য-সারি একবার ::, ছোট হাতের অক্ষর।
  2. সাধারণ গঠন: /48 সাইট + ১৬ বিট subnet ID = /64 LAN + ৬৪ বিট interface ID; ডকুমেন্টেশনে শুধু 2001:db8::/32.
  3. ধরন: global 2000::/3, link-local fe80::/10 (সবার থাকে), ULA fc00::/7, ::1, ::, multicast ff00::/8; broadcast নেই — solicited-node ff02::1:ffXX:XXXX, MAC 33:33:….
  4. Header ৪০ বাইট, checksum নেই, router ভাঙে না — Packet Too Big আর PMTUD, ন্যূনতম MTU ১২৮০; options extension header-এর শিকলে।
  5. NDP (RS, RA, NS, NA, Redirect) ARP-এর জায়গায়; DAD → RS → RA → SLAAC; M/O পতাকা DHCPv6 ঠিক করে; রূপান্তরে dual stack, tunnel, NAT64/DNS64, 464XLAT, Happy Eyeballs; NAT নেই, তাই firewall নীতি জরুরি।

পরের পর্বে: মডিউল ৩-এ দেখলেন ঠিকানা কীভাবে লেখা, ভাগ আর বসানো হয়। এবার মডিউল ৪ — router এত ঠিকানার মধ্যে কীভাবে পথ বেছে নেয়: routing table, static route আর longest prefix match, IPv4 আর IPv6 দুটিতেই।

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

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