Thuta Learning
Computer Networking
AdvancedDevOps & Toolsbeginner

IPv6 အခြေခံများ

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • IPv6 အခြေခံများ concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • Diagram ကို ဖတ်ပြီး packet/data ဘယ်လိုသွားလာသလဲ ခြေရာခံနိုင်ရန်
  • နမူနာ code ကို ကိုယ်တိုင် run ပြီး output စစ်နိုင်ရန်

နားလည်ထားရမယ့် အချက်

IPv4 မှာ bit ၃၂ လုံး ရှိပြီး address ၄.၃ ဘီလီယံခန့် ရှိတယ်၊ ပြီးတော့ အဲဒီထဲက အတော်များများဟာ ဘယ်တုန်းကမှ အသုံးမပြုနိုင်ခဲ့ဘူး။ Regional registry တွေဟာ လွန်ခဲ့တဲ့ နှစ်အတော်ကြာကတည်းက ကုန်သွားပြီ။ NAT က network တစ်ခုလုံးကို public address တစ်ခုနောက်မှာ ဝှက်ခွင့်ပြုခြင်းဖြင့် internet ကို နောက်ထပ် ဆယ်စုနှစ် နှစ်ခု ဝယ်ပေးခဲ့တယ်၊ ဒါပေမယ့် end-to-end ယူဆချက်ကို ချိုးဖျက်ပြီးမှ ဖြစ်တယ် — NAT နောက်က host တစ်ခုဆီ အပြင်ဘက်က တစ်စုံတစ်ခုက mapping တစ်ခု ဖွင့်မထားရင် ဆက်သွယ်လို့ မရဘူး — ဒါကြောင့်ပဲ peer-to-peer, VoIP နဲ့ game တွေ အားလုံးမှာ NAT ကို ကျော်ဖြတ်ဖို့ သီးသန့် တည်ရှိနေတဲ့ ရှုပ်ထွေးတဲ့ traversal ယန္တရားတွေ ပါလာတာ ဖြစ်တယ်။

IPv6 က bit ၁၂၈ လုံး သုံးတယ်။ Hex digit လေးလုံးစီပါတဲ့ group ရှစ်ခုကို colon နဲ့ ခြားပြီး ရေးတယ်။ ဒါကို တိုစေတဲ့ စည်းမျဉ်း နှစ်ခု ရှိတယ် — group တစ်ခုထဲက ရှေ့က သုည (leading zero) တွေကို ဖြုတ်လို့ ရတယ်၊ ပြီးတော့ သုညချည်း ဆက်တိုက်ဖြစ်နေတဲ့ group အစုတစ်ခုကို colon နှစ်ခုနဲ့ အစားထိုးလို့ ရတယ် — အတိအကျ တစ်ကြိမ်သာ။ ဒီ 'တစ်ကြိမ်သာ' ဆိုတာ အလှအပ ရွေးချယ်မှု မဟုတ်ဘူး — parsing လိုအပ်ချက် ဖြစ်တယ်။ Address တစ်ခုတည်းထဲမှာ colon နှစ်ခု နှစ်စုံ ပါရင် ဘယ်ဘက်မှာ သုည group ဘယ်နှခု၊ ညာဘက်မှာ ဘယ်နှခု ပါလဲ ဆိုတာ သိစရာ နည်းလမ်း မရှိတော့လို့ မရေရာသွားမယ်။ တစ်ခုဆိုရင် တွက်လို့ရတယ်၊ နှစ်ခုဆိုရင် မရဘူး။

IPv6 interface တိုင်းမှာ fe80:: နဲ့ စတဲ့ link-local address တစ်ခုပါ ရှိပြီး၊ အလိုအလျောက် ဖန်တီးထားကာ သူ့ကိုယ်ပိုင် segment ပေါ်မှာသာ တရားဝင်တယ်။ သူ့ကို ဘယ်တော့မှ route မလုပ်ဘူး၊ ပြီးတော့ neighbour discovery နဲ့ router advertisement တွေဟာ တကယ်တမ်း သူ့အပေါ်မှာ run နေတာ ဖြစ်တယ် — ဒါကြောင့် interface တစ်ခုမှာ အလုပ်လုပ်နေတဲ့ link-local address ရှိပြီး internet ကို လုံးဝ မရောက်နိုင်တာ ဖြစ်နိုင်တယ်။

Host တွေက global address ကို နည်းနှစ်မျိုးနဲ့ ရတယ်။ SLAAC မှာ router က prefix တစ်ခုကို ကြေညာပြီး host က သူ့ကိုယ်ပိုင် address ကို တည်ဆောက်တယ် — server မပါဝင်ဘူး။ DHCPv6 ကတော့ IPv4 ရဲ့ DHCP နဲ့ ပိုတူပြီး server တစ်ခုက သတ်မှတ် address တွေ ဝေပေးတယ်။ Network အများအပြားက နှစ်ခုလုံး သုံးကြတယ်။

ဘယ်သူမှ ခလုတ်တစ်ချက် နှိပ်ပြီး ပြောင်းလိုက်တာ မဟုတ်ဘူး။ ရွှေ့ပြောင်းရေး လမ်းကြောင်းက dual-stack ဖြစ်တယ် — protocol နှစ်ခုလုံး run ပါ၊ A နဲ့ AAAA record နှစ်ခုလုံး ထုတ်ပါ၊ ပြီးတော့ IPv6 အလုပ်လုပ်တဲ့အခါ client တွေက အဲဒါကို ဦးစားပေးပါစေ။

text
IPV4 VS IPV6 ADDRESS STRUCTURE AND COMPRESSION
----------------------------------------------
IPv4 -- 32 bits, four decimal octets

    203  .   0   .  113  .   42
   +-----------------+---------+
   |     network     |  host   |   boundary set by the mask
   +-----------------+---------+   (here: /24)


IPv6 -- 128 bits, eight hex groups of 16 bits

   2001 : 0db8 : abcd : 1234 : 0000 : 0000 : 0000 : 0010
   +--------------------------+--------------------------+
   |      /64 prefix          |  interface identifier    |
   +--------------------------+--------------------------+
    routing prefix + subnet     the host's own 64 bits


COMPRESSION, STEP BY STEP

   full         2001:0db8:0000:0000:0000:ff00:0042:8329
   drop zeros   2001:db8:0:0:0:ff00:42:8329
   collapse     2001:db8::ff00:42:8329
                         ^^
                         one run of zero groups, ONE time

   INVALID      2001:db8::1::2
                how many zero groups go on the left, and
                how many on the right? unanswerable, so
                a second '::' is forbidden outright.


ADDRESS KINDS ON ONE INTERFACE

   fe80::...    link-local  auto-made, never routed off-link
   2001:db8:... global      routable, from SLAAC or DHCPv6
   ::1          loopback    the IPv6 127.0.0.1
   ff02::1      multicast   all nodes on this link

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

သင် တကယ် ကြုံရမယ့် dual-stack ကျရှုံးမှု ပုံစံက တစ်စုံတစ်ယောက် AAAA record ထည့်ပြီးနောက် 'user တချို့အတွက် နှေးနေတယ်' ဆိုတဲ့ service တစ်ခု ဖြစ်တယ်။

ယန္တရားက ဒီလိုပါ။ AAAA record ထုတ်လိုက်တာဟာ client တိုင်းကို IPv6 ရနိုင်ကြောင်း ပြောလိုက်တာ ဖြစ်တယ်။ Happy Eyeballs ကို လိုက်နာတဲ့ client တွေက IPv6 ကို အရင် စမ်းပြီး၊ လမ်းကြောင်း ပျက်နေရင် IPv4 ဆီ ပြန်ဆင်းတယ် — ဒါပေမယ့် အဲဒီ ပြန်ဆင်းမှုက timeout တစ်ခု ကုန်ကျစေတယ် — ဒါကြောင့် တစ်ဝက်တစ်ပျက် ပျက်နေတဲ့ IPv6 လမ်းကြောင်းပေါ်က user တွေဟာ သင့် site ကို ပထမဆုံး ဆက်သွယ်တဲ့အခါ စက္ကန့်အနည်းငယ် ကြာနေမယ်၊ ကျန်တဲ့လူတွေကတော့ ပုံမှန်ပါပဲ။ ဒါကြောင့် AAAA record တစ်ခု ထည့်တာဟာ ကတိတစ်ခုပါ — အဲဒီ address ဟာ interface ပေါ်မှာ ရှိရုံသာမက public internet ကနေ တကယ် အလုပ်လုပ်ရမယ်။

သူ့ကို server အနေနဲ့ မဟုတ်ဘဲ client အနေနဲ့ စမ်းပါ။ အပြင် network တစ်ခုကနေ AAAA record ကို resolve လုပ်ပြီး curl -6 နဲ့ IPv6 ကို အတင်း သုံးခိုင်းကာ အဲဒီ address ကို တိုက်ရိုက် ဆက်သွယ်ကြည့်ပါ။ အဲဒါ ဆိုင်းငံ့နေပြီး curl -4 က အောင်မြင်နေရင် သင့် IPv6 လမ်းကြောင်း ပျက်နေတာမို့ ပြင်ပြီးတဲ့အထိ record ကို ဖြုတ်ထားသင့်တယ်။

နောက်ထပ် စောစော တည်ဆောက်သင့်တဲ့ အလေ့အထက bit ၃၂ လုံးလို့ မယူဆတဲ့ code ရေးဖို့ပါ။ Address တွေကို regex နဲ့ မဟုတ်ဘဲ library နဲ့ parse လုပ်ပါ၊ database column ကို စာလုံး ၄၅ လုံးအတွက် ချိန်ပါ၊ ပြီးတော့ URL တစ်ခုထဲက IPv6 address ကို bracket ခတ်ရမယ် ဆိုတာ မှတ်ထားပါ — http://[2001:db8::1]:8080/ — မဟုတ်ရင် colon တွေကို port ခြားတဲ့ သင်္ကေတအဖြစ် ဖတ်သွားလိမ့်မယ်။ အောက်က ဥပမာမှာ Python ရဲ့ ipaddress module ကို သုံးပြီး compression, expansion, prefix တွက်ချက်မှုနဲ့ dual-stack စစ်ဆေးမှုကို မိသားစု နှစ်ခုစလုံးအတွက် hardcode မလုပ်ဘဲ ပြထားတယ်။

အတူတူ စမ်းရေးကြည့်မယ်

python
import ipaddress

# Every one of these is the SAME address written differently. The rules:
# drop leading zeros in a group, and collapse ONE run of all-zero groups
# to '::'. Python always prints the canonical shortest form.
FORMS = [
    "2001:0db8:0000:0000:0000:ff00:0042:8329",
    "2001:db8:0:0:0:ff00:42:8329",
    "2001:db8::ff00:42:8329",
]

print("all three of these are one address:")
for text in FORMS:
    addr = ipaddress.IPv6Address(text)
    print("  " + text.ljust(40) + " -> " + str(addr))

print("")
# exploded shows every group padded back out -- useful when you need to
# eyeball a prefix boundary.
one = ipaddress.IPv6Address("2001:db8::ff00:42:8329")
print("compressed: " + str(one))
print("exploded:   " + one.exploded)
print("128 bits as an integer: " + str(int(one)))

print("")
# Why only ONE '::' is allowed: two of them would be ambiguous.
print("why only one '::':")
print("  2001:db8::1::2  would be unparseable -- 'how many zero groups")
print("  went on the left, and how many on the right?' has no answer.")
try:
    ipaddress.IPv6Address("2001:db8::1::2")
except ipaddress.AddressValueError:
    print("  python agrees: AddressValueError")

print("")
# Prefix math. /64 is the near-universal subnet size, which is why the
# second half of an address is called the interface identifier.
net = ipaddress.IPv6Network("2001:db8:abcd:1234::/64")
print("network:     " + str(net))
print("first addr:  " + str(net[0]))
print("host bits:   " + str(net.max_prefixlen - net.prefixlen))
print("addresses:   " + str(net.num_addresses))

print("")
# Address categories a host actually holds at once.
CANDIDATES = [
    "fe80::1c2b:3aff:fe4d:5e6f",
    "2001:db8:abcd:1234::10",
    "::1",
    "ff02::1",
]
for text in CANDIDATES:
    a = ipaddress.IPv6Address(text)
    kind = "global unicast"
    if a.is_link_local:
        kind = "link-local (SLAAC, never routed off-link)"
    elif a.is_loopback:
        kind = "loopback"
    elif a.is_multicast:
        kind = "multicast (all-nodes)"
    print("  " + text.ljust(26) + kind)

print("")
# Dual-stack: one name, two families. Code must handle both.
print("dual-stack host:")
for text in ["203.0.113.42", "2001:db8:abcd:1234::10"]:
    a = ipaddress.ip_address(text)
    print("  " + text.ljust(26) + "IPv" + str(a.version) +
          "  " + str(a.max_prefixlen) + " bits")
You should see
all three of these are one address:
  2001:0db8:0000:0000:0000:ff00:0042:8329  -> 2001:db8::ff00:42:8329
  2001:db8:0:0:0:ff00:42:8329              -> 2001:db8::ff00:42:8329
  2001:db8::ff00:42:8329                   -> 2001:db8::ff00:42:8329

compressed: 2001:db8::ff00:42:8329
exploded:   2001:0db8:0000:0000:0000:ff00:0042:8329
128 bits as an integer: 42540766411282592856904265327123268393

why only one '::':
  2001:db8::1::2  would be unparseable -- 'how many zero groups
  went on the left, and how many on the right?' has no answer.
  python agrees: AddressValueError

network:     2001:db8:abcd:1234::/64
first addr:  2001:db8:abcd:1234::
host bits:   64
addresses:   18446744073709551616

  fe80::1c2b:3aff:fe4d:5e6f link-local (SLAAC, never routed off-link)
  2001:db8:abcd:1234::10    global unicast
  ::1                       loopback
  ff02::1                   multicast (all-nodes)

dual-stack host:
  203.0.113.42              IPv4  32 bits
  2001:db8:abcd:1234::10    IPv6  128 bits

၅ မိနစ် စမ်းကြည့်

FORMS ထဲကို '2001:db8:0:0:1:0:0:1' ကို ထည့်ပြီး Python က ဘယ်သုည အစုကို ကျုံ့လိုက်လဲ ကြည့်ပါ — သုည အစု နှစ်ခု ရှိတဲ့အခါ ဘယ်ဟာကို ရွေးလဲ? ပြီးရင် /64 network ကို subnets(new_prefix=68) နဲ့ ခွဲကြည့်ပြီး ရလာတဲ့ subnet အရေအတွက်ကို print ထုတ်ပါ။

သတိလေးတစ်ချက်

IPv6 လမ်းကြောင်း အစအဆုံး အလုပ်မလုပ်သေးခင် AAAA record ထုတ်ခြင်း — client တွေက IPv6 ကို အရင် စမ်းလို့ user တွေ fallback timeout ကို ခံရတယ်။

Address တွေကို လက်ရေး regex နဲ့ စစ်ခြင်း ဒါမှမဟုတ် database column ကို စာလုံး ၁၅ လုံးအတွက် ချိန်ခြင်း — IPv6 text form က ၄၅ လုံးအထိ လိုပြီး တရားဝင် ရေးနည်း အများအပြား ရှိတယ်။

RFC 4291 - IP Version 6 Addressing ArchitectureComputer Networking

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • IPv6 လမ်းကြောင်း အစအဆုံး အလုပ်မလုပ်သေးခင် AAAA record ထုတ်ခြင်း — client တွေက IPv6 ကို အရင် စမ်းလို့ user တွေ fallback timeout ကို ခံရတယ်။
  • Address တွေကို လက်ရေး regex နဲ့ စစ်ခြင်း ဒါမှမဟုတ် database column ကို စာလုံး ၁၅ လုံးအတွက် ချိန်ခြင်း — IPv6 text form က ၄၅ လုံးအထိ လိုပြီး တရားဝင် ရေးနည်း အများအပြား ရှိတယ်။
  • နမူနာ code ကို production network ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

လေ့ကျင့်ခန်း

FORMS ထဲကို '2001:db8:0:0:1:0:0:1' ကို ထည့်ပြီး Python က ဘယ်သုည အစုကို ကျုံ့လိုက်လဲ ကြည့်ပါ — သုည အစု နှစ်ခု ရှိတဲ့အခါ ဘယ်ဟာကို ရွေးလဲ? ပြီးရင် /64 network ကို subnets(new_prefix=68) နဲ့ ခွဲကြည့်ပြီး ရလာတဲ့ subnet အရေအတွက်ကို print ထုတ်ပါ။

You'll know it worked when: all three of these are one address: 2001:0db8:0000:0000:0000:ff00:0042:8329 -> 2001:db8::ff00:42:8329 2001:db8:0:0:0:ff00:42:8329 -> 2001:db8::ff00:42:8329 2001:db8::ff00:42:8329 -> 2001:db8::ff00:42:8329 compressed: 2001:db8::ff00:42:8329 exploded: 2001:0db8:0000:0000:0000:ff00:0042:8329 128 bits as an integer: 42540766411282592856904265327123268393 why only one '::': 2001:db8::1::2 would be unparseable -- 'how many zero groups went on the left, and how many on the right?' has no answer. python agrees: AddressValueError network: 2001:db8:abcd:1234::/64 first addr: 2001:db8:abcd:1234:: host bits: 64 addresses: 18446744073709551616 fe80::1c2b:3aff:fe4d:5e6f link-local (SLAAC, never routed off-link) 2001:db8:abcd:1234::10 global unicast ::1 loopback ff02::1 multicast (all-nodes) dual-stack host: 203.0.113.42 IPv4 32 bits 2001:db8:abcd:1234::10 IPv6 128 bits

IPv6 အခြေခံများ | Thuta Learning