1 पॉइंट द्वारा GN⁺ 4 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • न्यूनतम कंटेनर इमेज में अक्सर curl या wget नहीं होते, इसलिए पैकेज इंस्टॉल किए बिना आंतरिक सर्विस कनेक्टिविटी जाँचने का वैकल्पिक तरीका उपयोगी होता है
  • Bash का /dev/tcp/host/port रीडायरेक्शन TCP socket खोल सकता है, इसलिए HTTP/1.1 अनुरोध स्ट्रिंग को सीधे लिखकर भेजा जा सकता है और response पढ़ा जा सकता है
  • /dev/tcp फ़ाइलसिस्टम path नहीं बल्कि Bash की आंतरिक सुविधा है, इसलिए ls /dev/tcp या दूसरे shell के सामान्य फ़ाइल access तरीके से यह काम नहीं करता
  • यह तरीका redirect, chunked response, compression, retry, TLS को संभालने वाला सरल debugging तरीका नहीं है, और Connection: close के बिना cat प्रतीक्षा में अटक सकता है
  • रोज़मर्रा के HTTP कामों के लिए curl सही है, लेकिन टूल जोड़ना मुश्किल हो ऐसे छोटे कंटेनर में तेज़ कनेक्शन जाँच के लिए यह पर्याप्त है

Bash फ़ाइल डिस्क्रिप्टर से HTTP अनुरोध लिखना

  • आंतरिक Docker नेटवर्क में किसी दूसरी सर्विस के /health endpoint तक पहुँच हो रही है या नहीं, यह जाँचना था, लेकिन इमेज में curl या wget नहीं थे
  • Bash TCP socket को फ़ाइल डिस्क्रिप्टर से जोड़ सकता है, इसलिए नीचे की तरह HTTP अनुरोध सीधे लिखकर भेजा जा सकता है
exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3
  • service ऐसा hostname होना चाहिए जिसे मौजूदा execution location से resolve और reach किया जा सके
    • यह Docker नेटवर्क में सेट किया गया container या service name हो सकता है
    • कोई resolve होने वाला DNS name भी इस्तेमाल किया जा सकता है
    • host और port को अपने environment के अनुसार बदलना होगा
  • response output में status line, headers, खाली पंक्ति और body साथ में शामिल होंगे
  • header जोड़ना हो तो अनुरोध समाप्त करने वाली खाली पंक्ति से पहले \r\n पर समाप्त होने वाली और पंक्तियाँ जोड़ दें
exec 3<>/dev/tcp/service/8642
printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3
cat <&3

/dev/tcp वास्तव में फ़ाइल क्यों नहीं है

  • /dev/tcp कोई वास्तविक device file नहीं, बल्कि Bash द्वारा संभाला जाने वाला रीडायरेक्शन है
    • डिस्क पर यह path मौजूद नहीं होता, इसलिए ls /dev/tcp विफल होगा
    • दूसरे shell में cat /dev/tcp/... चलाने पर भी त्रुटि मिलेगी
  • Bash manual के अनुसार, /dev/tcp/host/port में host वैध hostname या internet address हो और port पूर्णांक port number या service name हो, तो Bash TCP socket खोलने की कोशिश करता है
  • Bash DNS lookup और connect(2) करता है, और exec 3<> उस socket को फ़ाइल डिस्क्रिप्टर 3 से जोड़ देता है ताकि पढ़ना और लिखना दोनों संभव हों

HTTP क्लाइंट का विकल्प नहीं, अस्थायी जाँच का टूल

  • यह तरीका कोई वास्तविक HTTP client नहीं है, इसलिए redirect, chunked response, compression, retry, TLS आदि को संभालता नहीं है
  • Connection: close header महत्वपूर्ण है
    • इसके बिना server HTTP/1.1 के default व्यवहार के अनुसार कनेक्शन खुला रख सकता है
    • इस स्थिति में cat <&3 EOF का इंतज़ार करता रह सकता है और समाप्त नहीं होगा
  • timeout 6 bash -c '...' जैसी wrapping करने से उस स्थिति के लिए भी तैयार रहा जा सकता है जहाँ कनेक्शन बंद न हो
  • /dev/tcp raw socket खोलने का तरीका है, इसलिए यह केवल plain-text HTTP पर लागू होता है; https के लिए openssl s_client चाहिए
  • यह POSIX feature नहीं, Bash feature है, इसलिए Debian के /bin/sh यानी dash या zsh में इसका उपयोग नहीं किया जा सकता; bash को सीधे चलाना होगा
  • Bash build के समय --enable-net-redirections से सक्षम होने वाला compile-time option है
  • निष्कर्षतः, यह curl का सामान्य विकल्प कम और इंस्टॉलेशन जोड़े बिना काम चलाना हो ऐसे छोटे कंटेनर में तेज़ी से कनेक्टिविटी जाँचने का साधन ज़्यादा है

1 टिप्पणियां

 
GN⁺ 4 시간 전
Hacker News की राय
  • 90 के दशक के आखिर में बचपन में यह जानकर झटका लगा था कि telnet से 80, 25, 110 ports पर connect करके server से सीधे बात की जा सकती है
    साधारण GET / HTTP/1.1 request हाथ से टाइप कर सकते थे, या port 25 पर HELO, mail-from, mail-to से mail भेज सकते थे, और POP3 से mailbox listing और individual messages ला सकते थे
    यही अनुभव इस समझ की शुरुआत था कि “कोई जादू नहीं है”; computer का हर हिस्सा इंसानों ने बनाया है, और मेहनत करें तो एक हद तक उसे समझा जा सकता है
    भविष्य में ज़्यादातर काम agents को सौंप दिए जाएंगे, लेकिन जो लोग model और safety guardrails के filters के बिना असली काम करने का तरीका सीखना चाहते हैं, उनके लिए कई systems में दिलचस्प छेद बचे रहेंगे

    • DKIM/SPF न होने और SMTP server authentication ढीली होने के दौर में jacques.chirac@elysee.fr जैसे address से mail भेजकर दोस्तों के सामने hacker जैसा दिखा जा सकता था
    • उस समय सिर्फ DKIM या SPF ही नहीं थे, बल्कि ज़्यादातर SMTP servers open relay थे, जो किसी से भी किसी को भी mail accept कर लेते थे
    • आखिरकार यह सब सिर्फ text files ही हैं
      यह बस structured text files बनाने, भेजने और पढ़ने के कई तरीकों के ऊपर चढ़ी हुई ढेर सारी abbreviations की परत थी
      जिस दिन समझ आया कि database भी आखिर text file ही है, उस दिन थोड़ी देर बैठना पड़ा था
    • पिछली सदी में office में personal mail पढ़ने और भेजने के लिए telnet से POP3 और SMTP पर अलग-अलग connect करना पड़ता था
    • HTTP/2 में यह तरीका काम नहीं करता, लेकिन अच्छी बात है कि लगभग सभी servers अभी भी HTTP/1 बोल लेते हैं
      TLS भी telnet से नहीं होता, और कई servers HTTP requests पर सिर्फ redirect वापस देते हैं
      telnet की जगह openssl s_client इस्तेमाल करें तो TLS के भीतर text tunnel किया जा सकता है, लेकिन यह थोड़ा hack जैसा लगता है
      अफसोस यह भी है कि आज के कई modern protocols binary encoding को prefer करते हैं, इसलिए dedicated tools के बिना wire level पर उन्हें छेड़ना मुश्किल हो गया है
      फिर भी लगता है कि भविष्य में भी ऐसे लोग रहेंगे जो इसमें गहराई से उतरेंगे; डंडे से आग जलाना या मिट्टी की ईंट पकाना जैसी पुरानी skills मज़ेदार भी हैं और कभी-कभी सच में काम की भी
      बल्कि AI की वजह से experiments और आसान हो गए हैं; RFC खंगाले बिना भी LLM से पूछकर, जैसे कि, आम IMAP commands का बड़ा हिस्सा सीखा जा सकता है
  • zsh में Bash के /dev/tcp से अलग zsh/net/tcp और zsh/zftp modules भी हैं
    https://zsh.sourceforge.io/Doc/Release/TCP-Function-System.h...
    https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-...
    https://zsh.sourceforge.io/Doc/Release/Zftp-Function-System....

  • Plan 9 में सचमुच का synthetic file system /net था, इसलिए किसी भी program से यह काम और इससे भी ज़्यादा किया जा सकता था
    किसी दूसरी machine के /net को 9P protocol से mount करके उसे instant VPN की तरह भी इस्तेमाल किया जा सकता था, और Linux पर 9front के साथ इसका प्रयोग किया जा सकता है
    Go library में भी Plan 9 शैली के /net के निशान दिखते हैं, शायद यह Rob Pike की विरासत है

  • example.com पर यह ठीक से काम करता है
    exec 3<>/dev/tcp/example.com/80 से खोलें, फिर printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' >&3 भेजें, और उसके बाद cat <&3 करें तो HTTP/1.1 200 OK मिलता है
    आजकल ऐसे domains बहुत कम बचे हैं जो HTTPS को force नहीं करते, इसलिए ऐसे tests के लिए आखिरकार example.com पर जाना पड़ता है

    • public WiFi captive portal अटक जाए तब भी example.com काम आता है
      browser में http://example.com खोलने पर captive portal page पर redirect हो जाता है, जिससे internet access की प्रक्रिया फिर से पूरी की जा सकती है
    • printf के अंदर actual newline डालें तब भी यह काम करता है
      \r होना सही है, लेकिन उसे हटा दें तो भी काम चल जाता है
  • मज़ाक में कहा जा सकता है कि दोस्त के computer से बात करने के लिए सब bash -i >& /dev/tcp/IP/PORT 0>&1 का इस्तेमाल करते हैं

  • Bash HTTP नहीं बोलता, बल्कि TCP socket खोलने की सुविधा देता है
    यहाँ किया जा रहा काम सीधे HTTP बोलना है, जो test या debugging के लिए ठीक है, और हाथ से करके देखना मज़ेदार भी हो सकता है, लेकिन असली unattended environment में ऐसा नकली HTTP client इस्तेमाल करना आखिरकार भारी पड़ सकता है
    यह toy code HTTP को ठीक से parse नहीं करता, इसलिए टूट सकता है
    बेशक Bash में पूरा HTTP/1.1 client भी लिखा जा सकता है, और pure Bash HTTP server भी बनाया जा सकता है: https://github.com/bahamas10/bash-web-server
    कम पागलपन वाला विकल्प आम तौर पर nc होता है, और ज़्यादातर मामलों में वही ज़्यादा समझदारी भरा है

    • “pure Bash में पूरा HTTP server” कहना सख्ती से देखें तो गलत है
      Bash incoming connection स्वीकार करने के लिए TCP/UDP socket पर listen नहीं कर सकता
      bash-web-server project C में लिखा socket listener build करता है, और runtime पर उसे “built-in” module की तरह dynamically load करके यह सुविधा देता है
      [0] https://github.com/bahamas10/bash-web-server/tree/main/loada...
    • यह बात सही है, और पोस्ट की wording ज़रूरत से ज़्यादा थी, इसलिए इसे ज़्यादा सटीक रूप में update करने वाला हूँ
      nc या netcat जैसी कोई मिलती-जुलती utility बेहतर विकल्प होती, लेकिन उस समय इस्तेमाल की जा रही image में ऐसा कोई tool नहीं था
    • यह उतना भी पागलपन नहीं है
      HTTP/1.1 और ज़रूरी Host header आने से पहले से लोग हाथ से HTTP request टाइप करते रहे हैं
      गंभीर काम के लिए इसका इस्तेमाल करना पागलपन है, और Bash में web server बनाना भी वैसा ही है, लेकिन तेज़ testing के लिए यह काफ़ी अच्छा है
    • किसी ने pure Bash Minecraft server भी बनाया है
      https://sdomi.pl/weblog/15-witchcraft-minecraft-server-in-ba...
    • Bash के लिए Rails जैसा framework भी है: https://github.com/jneen/balls
  • मैंने यह तरीका Bauhinia team को CTF challenge solve करते देख कर सीखा
    वह कई चरणों वाला CTF था, और शुरुआत में ROP chain से system shell मिल जाती थी, लेकिन वह लगभग जेल जैसा environment था जहाँ Bash के अलावा व्यावहारिक रूप से कुछ भी चलाया नहीं जा सकता था
    इस्तेमाल करने लायक बस read और cat जैसे command थे, इसलिए cat /dev/tcp का उपयोग किया, फिर उसे virtual terminal पर redirect किया, और उसकी सामग्री पढ़कर internal system URL निकाला और flag ढूँढ़ लिया

  • internal Docker network में container के बीच connectivity चेक करते समय मुझे यह तरीका मिला, क्योंकि image में न curl था न wget
    हैरानी की बात यह थी कि Bash में /dev/tcp होता है, और थोड़ी shell magic से HTTP request जैसी चीज़ बनाई जा सकती है
    उदाहरण के लिए exec 3<>/dev/tcp/service/8642 से खोलें, फिर printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3 भेजें, और उसके बाद cat <&3 करें
    यहाँ service वह hostname है जिससे जुड़ना है, और 8642 वह port है जिस पर HTTP की तरह बात करने की कोशिश की जा रही है

    • यह बढ़िया है, लेकिन क्या ऐसी कोई कमी है कि सीधे curl support वाली image ही न इस्तेमाल की जाए?
      मुझे तो कोई कमी नहीं सूझती, और production image में भी मैं इसे लगभग ज़रूरी मानता हूँ
  • पुराने Debian और Debian-आधारित distro में यह सुविधा काम नहीं करती थी, क्योंकि virtual file के ज़रिए TCP access default रूप से disabled था
    मेरी समझ के अनुसार 2009 में रुख बदला गया और यह feature enable कर दिया गया, और Bug #146464 में चर्चा और link मौजूद हैं
    <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=146464#37>
    shell tool से network functionality तक सीधे पहुँचने के और भी कई तरीके हैं, जैसे curl, wget, Perl के HEAD और GET command, netcat/nc, socat, telnet आदि

  • किशोरावस्था में मुझे याद है कि मैं echo से दूसरे लोगों के /dev/ptty पर डरावने message भेजकर उन्हें चौंकाया करता था
    मेरे भेजे हुए message सामने वाले के खुले terminal पर जैसे जादू से प्रकट हो जाते थे
    आज तक नहीं समझ पाया कि computer lab में हर client के लिए अलग account देकर भी उन्हें lock क्यों नहीं किया गया था; शायद वह उस समय VAX की सीमा रही होगी