1 पॉइंट द्वारा GN⁺ 2025-03-05 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Linux में यूज़र स्पेस TCP/IP स्टैक खुद बनाते हुए network layers सीखने वाली सीरीज़ के पहले चरण के रूप में, Layer 2 के Ethernet frame handling और ARP response से implementation शुरू होती है
  • kernel का low-level network traffic TAP device से लिया जाता है, और लौटे हुए file descriptor के ज़रिए virtual device के Ethernet buffer को read/write किया जा सकता है
  • Ethernet header को dmac, smac, ethertype, payload के रूप में हैंडल किया जाता है, और अगर ethertype value 1536 या उससे अधिक हो तो payload type, उससे कम हो तो payload length दर्शाती है
  • ARP, IPv4 address जैसे protocol addresses को 48-bit MAC address से dynamically map करता है, और requests का जवाब देते समय translation table अपडेट करने के flow के रूप में implement होता है
  • arping test में custom stack के ARP response को Linux kernel पहचानता है और tap0 interface के ARP cache में 10.0.0.4 entry जुड़ जाती है

यूज़र स्पेस TCP/IP स्टैक की शुरुआत

  • लक्ष्य Linux में minimal user-space TCP/IP stack implement करते हुए networking और system programming को और गहराई से समझना है
  • TCP में 30 साल से अधिक समय में कई specifications जुड़कर complexity बढ़ी है, लेकिन core implementation elements को TCP header parsing, state machine, congestion control, और retransmission timeout calculation तक सीमित करके देखा जा सकता है
  • Ethernet और IP, TCP की तुलना में कम complex हैं, इसलिए सीरीज़ Layer 2 से implementation शुरू करती है

TAP device से Ethernet traffic लेना

  • Linux kernel के low-level network traffic को intercept करने के लिए Linux TAP device का उपयोग किया जाता है
  • TUN/TAP devices अक्सर user-space networking applications में क्रमशः L3/L2 traffic manipulate करने के लिए उपयोग होते हैं
    • tunneling वह तरीका है जिसमें packets को दूसरे packets के payload के अंदर wrap किया जाता है
    • OpenVPN जैसे programs भी TUN/TAP devices का उपयोग करते हैं
  • क्योंकि network stack Layer 2 से बनाया जा रहा है, इसलिए TUN नहीं बल्कि TAP device चाहिए
  • TAP device /dev/net/tap खोलकर और ioctl(fd, TUNSETIFF, ...) से create किया जाता है
    • IFF_TAP TAP device चुनता है
    • IFF_NO_PI Ethernet frame से पहले अनावश्यक packet information जुड़ने से रोकता है
  • create होने के बाद लौटे file descriptor fd से virtual device के Ethernet buffer को read और write किया जाता है

Ethernet frame format

  • Ethernet, LAN में computers को connect करने वाली foundational technology है, और पहला Ethernet standard 1980 में Digital Equipment Corporation, Intel, Xerox ने प्रकाशित किया था
  • पहला version लगभग 10Mb/s speed और half-duplex communication इस्तेमाल करता था, इसलिए data flow coordinate करने के लिए MAC protocol की ज़रूरत थी
    • half-duplex Ethernet interfaces में CSMA/CD MAC method के रूप में ज़रूरी था
    • 100BASE-T twisted-pair wiring का उपयोग करके full-duplex communication और higher throughput संभव बनाता है
    • Ethernet switches के व्यापक होने के साथ CSMA/CD की आवश्यकता आम तौर पर कम हो गई
  • Ethernet standard को IEEE 802.3 working group manage करता है

implementation में इस्तेमाल होने वाला Ethernet header

  • implementation Linux के if_ether.h को include करके ethertype और hexadecimal values की mapping का उपयोग करती है
  • Ethernet header को C struct में इन fields से represent किया जाता है
    • dmac: destination MAC address
    • smac: source MAC address
    • ethertype: payload length या type
    • payload: ARP या IPv4 packet रखने वाला payload pointer
  • ethertype एक 2-octet field है और value के आधार पर उसका अर्थ बदलता है
    • value 1536 या उससे अधिक हो तो IPv4, ARP जैसे payload type को दर्शाती है
    • value उससे कम हो तो payload length को दर्शाती है
  • Ethernet frame में VLAN या QoS दर्शाने वाले tags लग सकते हैं, लेकिन इस implementation में frame tags शामिल नहीं किए गए हैं
  • अगर payload length tags के बिना minimum required size 48 bytes से कम हो, तो अंत में padding bytes जोड़े जाते हैं
  • Ethernet Frame Format के अंत में CRC से integrity check करने वाला Frame Check Sequence field होता है, लेकिन इस implementation में उसे handle नहीं किया गया है

Ethernet frame parsing का तरीका

  • struct declaration का packed attribute GNU C compiler को data alignment के लिए padding bytes से struct memory layout optimize करने से रोकता है
  • implementation में parsing, buffer को appropriate protocol struct में type cast करने के तरीके से की जाती है
    • उदाहरण: struct eth_hdr *hdr = (struct eth_hdr *) buf;
  • अधिक portable तरीका protocol data को manually serialize करना है
    • इस स्थिति में compiler processor-specific data alignment requirements के अनुसार padding bytes जोड़ सकता है
  • received Ethernet frame processing एक सरल flow follow करती है
    • TAP device से buffer पढ़ना
    • init_eth_hdr(buf) से Ethernet header initialize करना
    • handle_frame(&netdev, hdr) ethertype value देखकर अगला action तय करता है

ARP packet structure और role

  • ARP(Address Resolution Protocol) IPv4 address जैसे protocol addresses को 48-bit Ethernet address यानी MAC address से dynamically map करता है
  • ARP केवल IPv4 तक सीमित नहीं है और कई L3 protocols के साथ इस्तेमाल किया जा सकता है
    • उदाहरण के लिए CHAOS 16-bit protocol address declare करता है
  • सामान्य LAN communication में service का IP address पता होने पर भी actual transmission के लिए MAC address चाहिए होता है
  • ARP network पर broadcast query भेजता है ताकि उस IP address का owner अपना hardware address announce करे

ARP header और IPv4 payload

  • ARP header इन fields से बना होता है
    • hwtype: link layer type दर्शाने वाला 2-octet field, Ethernet के लिए value 0x0001
    • protype: protocol type दर्शाने वाला 2-octet field, IPv4 के लिए value 0x0800
    • hwsize: hardware address size दर्शाने वाला 1-octet field, MAC address 6 bytes का होता है
    • prosize: protocol address size दर्शाने वाला 1-octet field, IPv4 address 4 bytes का होता है
    • opcode: ARP message type दर्शाने वाला 2-octet field
  • opcode value चार प्रकारों में बंटी है
    • ARP request: 1
    • ARP reply: 2
    • RARP request: 3
    • RARP reply: 4
  • IPv4 के लिए ARP data को arp_ipv4 struct से handle किया जाता है
    • smac: sender MAC address
    • sip: sender IP address
    • dmac: receiver MAC address
    • dip: receiver IP address

address resolution algorithm और cache

  • RFC 826 का address resolution algorithm hardware type और protocol type verify करने के बाद translation table update करता है, और target address खुद का हो तो response बनाने का flow अपनाता है
  • translation table ARP results store करती है ताकि host पहले से मौजूद entries को cache से lookup कर सके
  • यह cache duplicate ARP requests से network के अनावश्यक रूप से भरने को कम करता है
  • implementation code arp.c में है

ARP response test और अगला चरण

  • ARP implementation का final test यह check करना है कि request का सही जवाब मिलता है या नहीं
  • arping -I tap0 10.0.0.4 चलाने पर 10.0.0.4 से 00:0C:29:6D:50:25 MAC address के साथ unicast response वापस आता है
  • इसके बाद arp output में Linux kernel के ARP cache में 10.0.0.4 ether 00:0c:29:6d:50:25 tap0 entry बन जाती है
  • minimal Ethernet frame handling और ARP implementation भर से भी यह verify किया जा सकता है कि custom Ethernet device Linux host के ARP cache को populate करता है
  • project source code GitHub पर है, और अगला चरण ICMP echo/reply यानी ping और IPv4 packet parsing implement करना है

1 टिप्पणियां

 
GN⁺ 2025-03-05
Hacker News की राय
  • कुछ साल पहले मैंने C में user-space network stack बनाया था, और TUN interface के जरिए raw packets प्रोसेस करके उसे कुछ हद तक काम करने लायक बना लिया था
    अब इसमें एक साधारण shell है जिससे IP address, routes आदि सेट किए जा सकते हैं, और network packets को mbuf और sk_buf के मिश्रण जैसी hybrid structure में रखा जाता है
    हालांकि UDP implementation पूरा करने के बाद TCP implement करने का समय या उत्साह नहीं जुटा पाया, और code यहां है: https://github.com/cakturk/unet

    • बहुत पहले मैंने pcap/tcpdump parser pure bash में लिखा था, क्योंकि उस समय “program” लिखना मुझे बस उसी tool में आता था
      स्वाभाविक रूप से वह इतिहास की सबसे धीमी और नाजुक चीजों में से एक रहा होगा, लेकिन वह सचमुच काम करता था और काफी मजेदार भी था। काश उसका code अब भी कहीं बचा हो
    • कई embedded devices TCP/IP implementation के लिए lwip इस्तेमाल करते हैं
      lwip का “POSIX port” भी इसी तरह TUN/TAP device से raw Ethernet bytes लेता है
      https://github.com/lwip-tcpip/lwip/blob/master/contrib/ports...
  • अगर minimal Linux kernel को TCP/IP stack के बिना compile करें तो वह 400KB होता है, और TCP/IP stack जोड़ने पर 800KB हो जाता है
    ऐसे project में जहां सिर्फ temperature भेजना था, user-space में एक छोटे C program से खुद बनाए UDP message में value डालकर भेजी, जिससे space और complexity काफी घट गई

    • कुछ न जानने वाले के नजरिए से यह काफी हैरान करने वाला है; लेकिन इसका मतलब यह तो नहीं कि TCP/IP वाला हिस्सा पूरे kernel source code का आधा है, है ना?
    • हैरानी है कि IP stack इतना बड़ा क्यों है। 400KB binary में तो काफी code होगा; क्या यह बड़े server use cases के लिए बहुत ज्यादा optimized होने की वजह से है?
  • ARP disable करने पर एक ही network के कई servers पर वही IP सेट किया जा सकता है
    अगर routing frontend की भूमिका वाला server MAC address के आधार पर backend server के network interface तक packets forward कर सके, तो वह backend खुद को destination मानेगा और source/destination IP बदलकर client को सीधे reply कर सकता है। इस दौरान routing frontend से दोबारा नहीं गुजरना पड़ता
    या ARP बंद किए बिना भी common IP address को loopback interface के alias के रूप में जोड़कर यही असर पाया जा सकता है, और backend खुद को destination मानेगा जबकि ARP conflict से बचा रहेगा। यह 90s–00s में IBM WebSphere software load balancer की इस्तेमाल की हुई trick थी

    • Cisco IOS SLB भी मिलते-जुलते तरीके से काम कर सकता है। server farm के हर server loopback में virtual IP को alias के रूप में जोड़ने का तरीका है
      ज्यादा आम तौर पर इस्तेमाल होने वाली L3 load balancing की तुलना में फायदा यह है कि IP packet header को rewrite करने की जरूरत नहीं पड़ती
    • इसे DSR(Direct Server Return) के नाम से भी जाना जाता है: https://www.haproxy.com/blog/layer-4-load-balancing-direct-s...
    • ARP disable करके एक ही network के कई servers पर वही IP सेट करने पर switch/bridge MAC address सीख नहीं पाता, इसलिए वह उस segment के सभी ports पर packets को लगातार flood/broadcast करता रहता है
      इसलिए अगर यह तरीका अपनाना हो तो dedicated VLAN बनाना बेहतर है
    • F5 में ARP proxy setting होती है, इसलिए ऐसा करने की जरूरत नहीं पड़ती। कमी यह है कि यह अक्सर DHCP को खराब कर देती है
    • ऐसे low-level खेलों के लिए DPDK भी आजमाया जा सकता है। ARP default रूप से disabled होता है
  • मैंने ऐसा ही कुछ Python में किया था: https://github.com/georgek/notebooks/blob/master/internet.ip...
    शायद code quality उतनी अच्छी नहीं है, और सच कहूं तो address resolution algorithm भी बस अपने मन से बना लिया था। ICMP से internet host को ping भेजने तक सफल रहा
    मुझे यह बात पसंद है कि यह एक छोटे notebook में पूरा समा जाता है। मूल लेख referenced बड़े source code में मौजूद कई details को मुख्य text में छोड़ देता है
    मैंने यह लेख नहीं देखा था और सिर्फ Wikipedia देखकर बनाया था। हालांकि TCP से complexity काफी बढ़ जाती है, इसलिए रुचि थोड़ी कम हो गई। Part 3 उसी हिस्से को cover करता है, तो शायद कभी पढ़कर इसे पूरा करूं। Networking में रुचि हो तो किसी भी स्तर के programmer के लिए यह करने लायक और संतोषजनक काम है

  • कुछ साल पहले nuclear power plant instrumentation पर काम किया था। client-side development Sun workstation पर किया, और सच कहें तो TCP/IP experience की वजह से ही hire हुआ था; वह experience CMU की “Operating Systems” class से मिला था
    दूसरी तरफ plant computer एक minicomputer था जिसमें TCP/IP stack नहीं था, इसलिए उस team को अपना stack खुद बनाना पड़ा

  • लेख शुरू होने के करीब 1 मिनट बाद कहा जाता है कि “dmac और smac काफी self-evident fields हैं”, लेकिन जो reader नहीं जानता कि ये क्या हैं, वह वहीं छूट सकता है
    वह सोच सकता है, “यह लेख उन लोगों के लिए है जिनके लिए ये fields self-evident हैं। यह मेरे लिए नहीं है, इसलिए पढ़ना बंद कर देना चाहिए”

    • पूरा वाक्य है “dmac और smac काफी self-evident fields हैं। इनमें communication parties के MAC addresses होते हैं (क्रमशः destination और source)”, इसलिए असल में यह समझाया गया है
      इसके अलावा, अगर यह network stack बनाने पर लेख है, तो यह मान लेना सुरक्षित है कि reader को networking के बारे में कुछ हद तक जानकारी है
    • अगर अभी-अभी update नहीं हुआ है, तो ठीक अगले वाक्य में “इनमें communication parties के MAC addresses होते हैं (क्रमशः destination और source)” समझाया गया है
  • संबंधित पोस्ट:
    Let’s code a TCP/IP stack (2016) - https://news.ycombinator.com/item?id=27654182 - जून 2021, 49 comments
    Let’s code a TCP/IP stack, 1: Ethernet & ARP (2016) - https://news.ycombinator.com/item?id=17316487 - जून 2018, 47 comments
    Let’s Code a TCP/IP Stack: TCP Retransmission - https://news.ycombinator.com/item?id=14701199 - जुलाई 2017, 30 comments
    Let’s code a TCP/IP stack, 1: Ethernet and ARP - https://news.ycombinator.com/item?id=11234229 - मार्च 2016, 49 comments

  • पता नहीं लेखक ने ARP resolution test में इस्तेमाल किया गया 10.0.0.4 IP address कहाँ से लिया
    यह किसका address है? क्या यह यहाँ बनाए गए fake Ethernet device से access किया जा सकने वाला कोई fake device है, या लेखक के network में सचमुच मौजूद कोई device?

    • लेख में नहीं बताया गया है, लेकिन यह वह value है जिसे लेखक ने interface initialization के समय hardcode किया था: https://github.com/saminiir/level-ip/blob/e9ceb08f01a5499b85...
      TAP device software से emulate किए गए Ethernet link जैसा होता है। अगर आप packet वहाँ भेजते हैं, तो वह सीधे user-level program को deliver होता है, और उस program से तय होता है कि उसका कौन-सा IP address होगा और वह ARP को कैसे respond करेगा
      आम तौर पर operating system ऐसी चीज़ों को संभालता है, और interface में IP address जोड़ने के लिए root privileges चाहिए होते हैं। TAP device खोलने के लिए भी यही लागू होता है। Networking आम तौर पर cooperative तरीके से चलती है, और network पर root privileges वाला malicious actor बुरी हरकतें कर सकता है
  • मेरी याद के अनुसार ARP केवल local segment में काम करता है। Router अपना address भरकर packet forward करता है
    rarp भी होता है, जो “network” से अपना IP address पूछने के तरीकों में से एक है। मुझे नहीं पता कि rarp आज भी real-world environments में काम करता है या नहीं