TCP/IP स्टैक कोडिंग 1: Ethernet और ARP (2016)
(saminiir.com)- 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के रूप में हैंडल किया जाता है, और अगरethertypevalue 1536 या उससे अधिक हो तो payload type, उससे कम हो तो payload length दर्शाती है - ARP, IPv4 address जैसे protocol addresses को 48-bit MAC address से dynamically map करता है, और requests का जवाब देते समय translation table अपडेट करने के flow के रूप में implement होता है
arpingtest में custom stack के ARP response को Linux kernel पहचानता है औरtap0interface के ARP cache में10.0.0.4entry जुड़ जाती है
यूज़र स्पेस 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_TAPTAP device चुनता हैIFF_NO_PIEthernet 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 addresssmac: source MAC addressethertype: payload length या typepayload: 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 का
packedattribute 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)ethertypevalue देखकर अगला 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 के लिए value0x0001protype: protocol type दर्शाने वाला 2-octet field, IPv4 के लिए value0x0800hwsize: 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
opcodevalue चार प्रकारों में बंटी है- ARP request:
1 - ARP reply:
2 - RARP request:
3 - RARP reply:
4
- ARP request:
- IPv4 के लिए ARP data को
arp_ipv4struct से handle किया जाता हैsmac: sender MAC addresssip: sender IP addressdmac: receiver MAC addressdip: 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:25MAC address के साथ unicast response वापस आता है- इसके बाद
arpoutput में Linux kernel के ARP cache में10.0.0.4 ether 00:0c:29:6d:50:25 tap0entry बन जाती है - 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 टिप्पणियां
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
स्वाभाविक रूप से वह इतिहास की सबसे धीमी और नाजुक चीजों में से एक रहा होगा, लेकिन वह सचमुच काम करता था और काफी मजेदार भी था। काश उसका code अब भी कहीं बचा हो
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 काफी घट गई
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 थी
ज्यादा आम तौर पर इस्तेमाल होने वाली L3 load balancing की तुलना में फायदा यह है कि IP packet header को rewrite करने की जरूरत नहीं पड़ती
इसलिए अगर यह तरीका अपनाना हो तो dedicated VLAN बनाना बेहतर है
मैंने ऐसा ही कुछ 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 हैं। यह मेरे लिए नहीं है, इसलिए पढ़ना बंद कर देना चाहिए”
इसके अलावा, अगर यह network stack बनाने पर लेख है, तो यह मान लेना सुरक्षित है कि reader को networking के बारे में कुछ हद तक जानकारी है
संबंधित पोस्ट:
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?
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 में काम करता है या नहीं