
SwiftNIO SSH, SwiftNIO का उपयोग करके SSH का एक प्रोग्रामेटिक कार्यान्वयन है।
इस प्रोजेक्ट में SwiftNIO का उपयोग करके SSH समर्थन शामिल है।
SwiftNIO SSH, SSH का एक प्रोग्रामेटिक कार्यान्वयन है: अर्थात्, यह API का एक संग्रह है जो प्रोग्रामरों को SSH-बोलने वाले एंडपॉइंट लागू करने की अनुमति देता है। महत्वपूर्ण रूप से, इसका मतलब है कि यह openssh की तुलना में libssh2 की तरह अधिक है। SwiftNIO SSH उत्पादन-तैयार SSH क्लाइंट और सर्वर नहीं भेजता है, बल्कि इस प्रकार के क्लाइंट और सर्वर बनाने के लिए बिल्डिंग ब्लॉक्स प्रदान करता है।
प्रोग्रामेटिक SSH कार्यान्वयन प्रदान करने के कई कारण हैं। एक यह है कि SSH का उपयोगकर्ता अंतःक्रियाशीलता से एक अनोखा संबंध है। तकनीकी उपयोगकर्ता SSH के साथ इंटरैक्टिव रूप से बातचीत करने के काफी आदी हैं, या तो दूरस्थ मशीनों पर कमांड चलाने के लिए या इंटरैक्टिव शेल चलाने के लिए। इन अनुरोधों का प्रोग्रामेटिक रूप से जवाब देने की क्षमता होने से बातचीत के दिलचस्प वैकल्पिक तरीके सक्षम होते हैं। पिछले उदाहरणों के रूप में, हम Twisted के Manhole की ओर इशारा कर सकते हैं, जो एक चालू Python सर्वर के भीतर एक इंटरैक्टिव Python इंटरप्रेटर प्रदान करने के लिए एक प्रोग्रामेटिक SSH कार्यान्वयन जिसे conch कहा जाता है का उपयोग करता है, या ssh-chat, एक SSH सर्वर जो नियमित SSH शेल कार्यक्षमता के बजाय एक चैट रूम प्रदान करता है। TCP अग्रेषण के लिए भी नवीन उपयोगों की कल्पना की जा सकती है।
प्रोग्रामेटिक SSH प्रदान करने का एक और अच्छा कारण यह है कि सेवाओं के लिए कमांड चलाने वाले तरीके से अन्य सेवाओं के साथ बातचीत करना असामान्य नहीं है। जबकि Process इसे स्थानीय उपयोग-मामले के लिए हल करता है, कभी-कभी जिन कमांडों को लागू करने की आवश्यकता होती है वे दूरस्थ होते हैं। जबकि Process इस आह्वान को चलाने के लिए एक उप-प्रक्रिया के रूप में एक ssh क्लाइंट लॉन्च कर सकता है, SSH को सीधे कॉल करना काफी अधिक सीधा हो सकता है। यह libssh2 का लक्षित उपयोग-मामला है। SwiftNIO SSH libssh2 के नेटवर्किंग और क्रिप्टोग्राफ़िक परत के समतुल्य प्रदान करता है, जिससे प्रेरित उपयोगकर्ता सीधे Swift सेवाओं के भीतर SSH सत्र चला सकते हैं।
SwiftNIO SSH के सबसे हाल के संस्करण Swift 5.9 और नए का समर्थन करते हैं। SwiftNIO SSH रिलीज़ द्वारा समर्थित न्यूनतम Swift संस्करण नीचे विस्तृत हैं:
SwiftNIO SSH निम्नलिखित फीचर सेट के साथ SSHv2 का समर्थन करता है:
SwiftNIO SSH एक SwiftNIO ChannelHandler, NIOSSHHandler प्रदान करता है। यह हैंडलर SSH प्रोटोकॉल के अधिकांश भाग को सीधे लागू करता है। उपयोगकर्ताओं से SSH संदेशों को सीधे उत्पन्न करने की अपेक्षा नहीं की जाती है: इसके बजाय, वे चाइल्ड चैनलों और डेलीगेट्स के माध्यम से NIOSSHHandler के साथ बातचीत करते हैं।
SSH एक मल्टीप्लेक्स्ड प्रोटोकॉल है: प्रत्येक SSH कनेक्शन को कई द्विदिश संचार चैनलों में विभाजित किया जाता है, जिन्हें उचित रूप से चैनल कहा जाता है। SwiftNIO SSH एक "चाइल्ड चैनल" अमूर्तता का उपयोग करके इस निर्माण को प्रतिबिंबित करता है। जब कोई पीयर एक नया SSH चैनल बनाता है, तो SwiftNIO SSH एक नया NIO Channel बनाएगा जो उस SSH चैनल पर सभी ट्रैफ़िक का प्रतिनिधित्व करने के लिए उपयोग किया जाता है। इस चाइल्ड Channel के भीतर सभी ईवेंट एक दूसरे के सापेक्ष सख्ती से क्रमबद्ध होते हैं: हालाँकि, विभिन्न Channels में ईवेंट को कार्यान्वयन द्वारा स्वतंत्र रूप से इंटरलीव किया जा सकता है।
इसलिए एक सक्रिय SSH कनेक्शन इस तरह दिखता है:
┌ ─ NIO Channel ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
│ ┌────────────────────────────────┐ │
│ │
│ │ │ │
│ │
│ │ │ │
│ NIOSSHHandler │───────────────────────┐
│ │ │ │ │
│ │ │
│ │ │ │ │
│ │ │
│ └────────────────────────────────┘ │ │
│
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │
│
│
│
│
▼
┌── SSH Child Channel ─────────────────────────────────────────────────────────────┐
│ │
│ ┌────────────────────────────────┐ ┌────────────────────────────────┐ ├───┐
│ │ │ │ │ │ │
│ │ │ │ │ │ ├───┐
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ User Handler │ │ User Handler │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ └────────────────────────────────┘ └────────────────────────────────┘ │ │ │
│ │ │ │
└───┬──────────────────────────────────────────────────────────────────────────────┘ │ │
│ │ │
└───┬──────────────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────────┘
एक SSH चैनल को एक चैनल प्रकार के साथ आह्वान किया जाता है। NIOSSH तीन का समर्थन करता है: session, directTCPIP, और forwardedTCPIP। सबसे आम चैनल प्रकार session है: session का उपयोग किसी प्रोग्राम के आह्वान का प्रतिनिधित्व करने के लिए किया जाता है, चाहे वह कोई विशिष्ट नामित प्रोग्राम हो या शेल। अन्य दो चैनल प्रकार TCP पोर्ट अग्रेषण से संबंधित हैं, और बाद में चर्चा की जाएगी।
एक SSH चैनल एक ही डेटा प्रकार पर काम करता है: SSHChannelData। यह संरचना इस तथ्य को समाहित करती है कि SSH नियमित और "विस्तारित" चैनल डेटा दोनों का समर्थन करता है। नियमित चैनल डेटा (SSHChannelData.DataType.channel) अधिकांश कोर डेटा के लिए उपयोग किया जाता है। session चैनलों में .channel डेटा प्रकार मानक इनपुट और मानक आउटपुट के लिए उपयोग किया जाता है: .stdErr डेटा प्रकार मानक त्रुटि के लिए उपयोग किया जाता है (स्वाभाविक रूप से)। TCP अग्रेषण चैनलों में, .channel डेटा प्रकार एकमात्र प्रकार है जिसका उपयोग किया जाता है, और यह अग्रेषित डेटा का प्रतिनिधित्व करता है।
एक session चैनल एक कमांड के आह्वान का प्रतिनिधित्व करता है। चैनल वास्तव में कैसे संचालित होता है, यह कई इनबाउंड उपयोगकर्ता ईवेंट्स में संप्रेषित किया जाता है। निम्नलिखित ईवेंट महत्वपूर्ण हैं:
SSHChannelRequestEvent.PseudoTerminalRequest: एक स्यूडो-टर्मिनल के आवंटन का अनुरोध करता है।SSHChannelRequestEvent.EnvironmentRequest: कमांड आह्वान के लिए एकल पर्यावरण चर का अनुरोध करता है। हमेशा कमांड से पहले भेजा जाता है।SSHChannelRequestEvent.ShellRequest: अनुरोध करता है कि आह्वान की जाने वाली कमांड प्रमाणित उपयोगकर्ता का शेल है।SSHChannelRequestEvent.ExecRequest: एक विशिष्ट कमांड के आह्वान का अनुरोध करता है।SSHChannelRequestEvent.ExitStatus: यह संकेत देने के लिए उपयोग किया जाता है कि दूरस्थ कमांड बाहर निकल गया है, और निकास कोड संप्रेषित करता है।SSHChannelRequestEvent.ExitSignal: यह इंगित करने के लिए उपयोग किया जाता है कि दूरस्थ कमांड एक सिग्नल के जवाब में समाप्त कर दिया गया था, और वह सिग्नल क्या था।SSHChannelRequestEvent.SignalRequest: दूरस्थ कमांड को सिग्नल भेजने के लिए उपयोग किया जाता है।SSHChannelRequestEvent.LocalFlowControlRequest: यह इंगित करने के लिए उपयोग किया जाता है कि क्या क्लाइंट स्वयं Ctrl-Q/Ctrl-S फ्लो नियंत्रण करने में सक्षम है।SSHChannelRequestEvent.WindowChangeRequest: क्लाइंट पर टर्मिनल विंडो के आकार में परिवर्तन को आवंटित स्यूडो-टर्मिनल तक संप्रेषित करने के लिए उपयोग किया जाता है।ये ईवेंट पोर्ट अग्रेषण संदेशों में उपयोग नहीं किए जाते हैं। SSH कार्यान्वयन जो .session प्रकार के चैनलों का समर्थन करते हैं, उन्हें इनमें से अधिकांश या सभी को विभिन्न तरीकों से संभालने के लिए तैयार रहने की आवश्यकता है।
इनमें से प्रत्येक ईवेंट में एक wantReply फ़ील्ड भी होता है। यह इंगित करता है कि क्या अनुरोध को सफलता या विफलता इंगित करने के लिए उत्तर की आवश्यकता है। यदि ऐसा है, तो निम्नलिखित दो ईवेंट उपयोग किए जाते हैं:
ChannelSuccessEvent, सफलता संप्रेषित करने के लिए।ChannelFailureEvent, विफलता संप्रेषित करने के लिए।SSH नेटवर्क प्रोटोकॉल चाइल्ड चैनलों में व्यापक रूप से हाफ-क्लोज़र का उपयोग करता है। NIO Channels में आमतौर पर डिफ़ॉल्ट रूप से हाफ-क्लोज़र समर्थन अक्षम होता है, और SwiftNIO SSH अपने चाइल्ड चैनलों में भी इस डिफ़ॉल्ट का सम्मान करता है। हालाँकि, यदि आप इस सेटिंग को इसके डिफ़ॉल्ट मान पर छोड़ देते हैं, तो SSH चाइल्ड चैनल बेहद अप्रत्याशित व्यवहार करेंगे। इस कारण से, यह दृढ़ता से अनुशंसित है कि सभी चाइल्ड चैनलों में हाफ क्लोज़र समर्थन सक्षम हो:
channel.setOption(ChannelOptions.allowRemoteHalfClosure, true)
यह तब मानक NIO हाफ-क्लोज़र समर्थन का उपयोग करता है। दूरस्थ पीयर द्वारा EOF भेजने को एक इनबाउंड उपयोगकर्ता ईवेंट, ChannelEvent.inputClosed के साथ संप्रेषित किया जाएगा। स्वयं EOF भेजने के लिए, close(mode: .output) को कॉल करें।
उपयोगकर्ता प्रमाणीकरण SSH का एक महत्वपूर्ण हिस्सा है। इसे प्रबंधित करने के लिए, SwiftNIO SSH डेलीगेट प्रोटोकॉल की एक जोड़ी का उपयोग करता है: NIOSSHClientUserAuthenticationDelegate और NIOSSHServerUserAuthenticationDelegate। क्लाइंट और सर्वर को उपयोगकर्ता प्रमाणीकरण प्रबंधित करने के लिए इन डेलीगेट प्रोटोकॉल के कार्यान्वयन प्रदान करने चाहिए।
क्लाइंट प्रोटोकॉल सीधा है: SwiftNIO SSH डेलीगेट पर विधि nextAuthenticationType(availableMethods:nextChallengePromise:) को आह्वान करेगा। availableMethods, NIOSSHAvailableUserAuthenticationMethods का एक उदाहरण होगा जो यह संप्रेषित करता है कि सर्वर ने कौन से प्रमाणीकरण तरीकों को स्वीकार्य सुझाया है। डेलीगेट तब nextChallengePromise को या तो एक नए प्रमाणीकरण अनुरोध के साथ, या nil के साथ पूरा कर सकता है ताकि यह संकेत दिया जा सके कि क्लाइंट के पास आज़माने के लिए कुछ भी नहीं बचा है।
सर्वर प्रोटोकॉल अधिक जटिल है। डेलीगेट को एक supportedAuthenticationMethods प्रॉपर्टी प्रदान करनी चाहिए जो संप्रेषित करती है कि डेलीगेट द्वारा कौन से प्रमाणीकरण तरीकों का समर्थन किया जाता है। फिर, जब भी क्लाइंट एक उपयोगकर्ता प्रमाणीकरण अनुरोध भेजता है, requestReceived(request:responsePromise:) विधि को आह्वान किया जाएगा। इसे समानांतर में कई बार आह्वान किया जा सकता है, क्योंकि क्लाइंट को समानांतर में प्रमाणीकरण अनुरोध जारी करने की अनुमति है। responsePromise को प्रमाणीकरण के परिणाम के साथ सफल किया जाना चाहिए। तीन परिणाम हैं: .success और .failure सीधे हैं, लेकिन सिद्धांत रूप में सर्वर .partialSuccess(remainingMethods:) का उपयोग करके कई चुनौतियों की आवश्यकता कर सकता है।
डायरेक्ट पोर्ट अग्रेषण क्लाइंट से सर्वर तक पोर्ट अग्रेषण है। इस मोड में परंपरागत रूप से क्लाइंट एक स्थानीय पोर्ट पर सुनेगा, और इनबाउंड कनेक्शनों को सर्वर पर अग्रेषित करेगा। यह पूछेगा कि सर्वर इन कनेक्शनों को एक विशिष्ट होस्ट और पोर्ट पर आउटबाउंड कनेक्शन के रूप में अग्रेषित करे।
इन चैनलों को क्लाइंट द्वारा .directTCPIP चैनल प्रकार का उपयोग करके सीधे खोला जा सकता है।
रिमोट पोर्ट अग्रेषण एक कम-सामान्य स्थिति है जहाँ क्लाइंट सर्वर से एक विशिष्ट पते और पोर्ट पर सुनने और सभी इनबाउंड कनेक्शनों को क्लाइंट को अग्रेषित करने के लिए कहता है। चूँकि क्लाइंट को इस व्यवहार का अनुरोध करने की आवश्यकता है, यह ग्लोबल अनुरोधों का उपयोग करके ऐसा करता है।
ग्लोबल अनुरोध NIOSSHHandler.sendGlobalRequest का उपयोग करके शुरू किए जाते हैं, और GlobalRequestDelegate के माध्यम से प्राप्त और संभाले जाते हैं। आज दो ग्लोबल अनुरोध समर्थित हैं:
GlobalRequest.TCPForwardingRequest.listen(host:port:): किसी दिए गए होस्ट और पोर्ट पर सर्वर द्वारा सुनने का अनुरोध।GlobalRequest.TCPForwardingRequest.cancel(host:port:): दिए गए होस्ट और पोर्ट पर सुनने को रद्द करने का अनुरोध।सर्वर को GlobalRequestDelegate का उपयोग करके इन अनुरोधों के बारे में सूचित किया जा सकता है और उनका जवाब दिया जा सकता है। यहाँ लागू करने की विधि tcpForwardingRequest(_:handler:promise:) है। यह डेलीगेट विधि हर बार एक ग्लोबल अनुरोध प्राप्त होने पर आह्वान की जाएगी। अनुरोध का उत्तर promise में पारित किया जाता है।
अग्रेषित चैनल तब .forwardedTCPIP चैनल प्रकार का उपयोग करके सर्वर से क्लाइंट को भेजे जाते हैं।
| SwiftNIO SSH | न्यूनतम Swift संस्करण |
|---|
0.0.0 ..< 0.3.0 | 5.1 |
0.3.0 ..< 0.4.0 | 5.2 |
0.4.0 ..< 0.5.0 | 5.4 |
0.5.0 ..< 0.6.2 | 5.5.2 |
0.6.2 ..< 0.9.0 | 5.6 |
0.9.0 ..< 0.9.2 | 5.8 |
0.9.2 ..< 0.10.0 | 5.9 |
0.10.0 ... 0.12.0 | 5.10 |
0.12.0 ..< 0.13.0 | 6.0 |
0.13.0 ..< | 6.1 |
SSHChannelRequestEvent.SubsystemRequest: किसी विशिष्ट सबसिस्टम के आह्वान का अनुरोध करने के लिए उपयोग किया जाता है। इसका अर्थ व्यक्तिगत उपयोग-मामलों के लिए विशिष्ट है।