Vielleicht fällt es Ihnen schwer, im Internet einen Artikel zu finden, der die Intranet-Penetration auf Code-Ebene erklärt. Ich habe erfolglos danach gesucht und deshalb diesen Artikel geschrieben. 1. Proxy im LAN Lassen Sie uns zunächst den vorherigen Artikel noch einmal durchgehen. Wie implementiere ich einen Service-Proxy in einem lokalen Netzwerk? Da dies sehr einfach ist, gehen wir direkt zum Code. const net = erfordern('net') const proxy = net.createServer(socket => { const localServe = neues net.Socket() localServe.connect(5502, '192.168.31.130') // Service-Port und IP im LAN. socket.pipe(localServe).pipe(socket) }) Proxy.Listen(80) Dies ist ein sehr einfacher serverseitiger Proxy. Der Code ist einfach und klar. Wenn Sie Fragen haben, liegt es wahrscheinlich an der Pipe hier. Lassen Sie es mich kurz erklären. Der Socket ist ein Vollduplex-Stream, also ein Datenstrom, der sowohl lesbar als auch beschreibbar sein kann. Wenn der Socket im Code Daten vom Client empfängt, schreibt er diese in den lokalen Server. Wenn der lokale Server Daten hat, schreibt er diese in den Socket und der Socket sendet die Daten dann an den Client. 2. Intranet-Penetration Ein LAN-Proxy ist einfach, aber die Intranet-Penetration ist nicht so einfach. Es handelt sich jedoch um den Kerncode und erfordert eine erhebliche logische Verarbeitung. Bevor wir es konkret umsetzen, klären wir zunächst die Intranet-Durchdringung. Was ist Intranet-Penetration? Einfach ausgedrückt handelt es sich dabei um einen öffentlichen Netzwerkclient, der auf Dienste innerhalb des lokalen Netzwerks zugreifen kann. Beispielsweise wurden Dienste lokal gestartet. Woher kennt der öffentliche Netzwerkclient den lokal gestarteten Server? Hier müssen wir auf die öffentlichen Netzserver zurückgreifen. Woher weiß der öffentliche Netzwerkserver also vom lokalen Dienst? Hierzu ist die Herstellung einer Socket-Verbindung zwischen der lokalen Umgebung und dem Server erforderlich. Vier Rollen Durch die obige Beschreibung stellen wir vier Rollen vor.
Um Client und localServe müssen wir uns dabei nicht kümmern, da es sich beim Client um einen Browser oder etwas anderes handeln kann und localServe nur ein gewöhnlicher lokaler Dienst ist. Wir müssen uns nur um ProxyServe und Bridge kümmern. Was wir hier vorstellen, ist immer noch die einfachste Implementierungsmethode und bietet eine Denk- und Denkweise. Beginnen wir also mit der einfachsten. Brücke Aus dem Abschnitt zu den vier Rollen wissen wir, dass Bridge eine Socket-Verbindung mit ProxyServe ist und die Datenübertragung ermöglicht. Sehen wir uns den Code an, um die Ideen zu klären. const net = erfordern('net') const proxyServe = "10.253.107.245" const bridge = neues Netz.Socket() bridge.connect(80, proxyServe, _ => { bridge.write('GET /regester?key=sq HTTP/1.1\r\n\r\n') }) bridge.on('Daten', Daten => { const localServer = neues net.Socket() localServer.connect(8088, 'localhost', _ => { localServer.write(Daten) localServer.on('Daten', res => bridge.write(res)) }) }) Der Code ist klar und lesbar, sogar eingängig. Importieren Sie die Netzbibliothek, deklarieren Sie die öffentliche Netzwerkadresse, erstellen Sie eine Brücke, verbinden Sie die Brücke mit ProxyServe und registrieren Sie nach erfolgreichem Abschluss den lokalen Dienst bei ProxyServe. Anschließend wartet die Brücke auf Daten und stellt bei Eingang einer Anforderung eine Verbindung mit dem lokalen Dienst her. Nach erfolgreichem Abschluss werden die Anforderungsdaten an LocalServe gesendet, gleichzeitig werden die Antwortdaten abgehört und der Antwortstrom in die Brücke geschrieben. Zum Rest gibt es nicht viel zu erklären, schließlich handelt es sich hier nur um Beispielcode. Im Beispielcode gibt es jedoch einen Abschnitt /regester?key=sq. Dieser Schlüssel ist sehr nützlich. Hier key=sq. Wenn der Rollenclient dann über den Proxydienst auf den lokalen Dienst zugreift, muss dieser Schlüssel dem Pfad hinzugefügt werden, damit der ProxyServe der Bridge und somit dem lokalen Dienst entsprechen kann. Beispiel: lcoalServe ist: http://localhost:8088, rpoxyServe ist example.com und der registrierte Schlüssel ist sq. Wenn Sie dann über prxoyServe auf localServe zugreifen möchten, müssen Sie es wie folgt schreiben: example.com/sq. Warum so schreiben? Natürlich ist dies nur eine Definition. Nachdem Sie den Code in diesem Artikel verstanden haben, können Sie diese Konvention ändern. Schauen wir uns also die folgenden Schlüsselcodes an: ProxyServe Obwohl der ProxyServe hier ein vereinfachter Beispielcode ist, ist er dennoch etwas kompliziert zu erklären. Wenn Sie ihn vollständig verstehen und mit Ihrem eigenen Unternehmen kombinieren möchten, um einen verwendbaren Code zu erstellen, müssen Sie einige Anstrengungen unternehmen. Hier teile ich den Code in Teile auf und versuche, ihn klar zu erklären. Wir geben den Codeblöcken Namen, um die Erklärung zu erleichtern. Die Hauptfunktion dieses Blocks besteht darin, einen Proxy-Dienst zu erstellen, eine Socket-Verbindung mit dem Client und der Bridge herzustellen, die Datenanforderung auf dem Socket abzuhören und eine logische Verarbeitung in der Rückruffunktion durchzuführen. Der spezifische Code lautet wie folgt: const net = erfordern('net') const bridges = {} // Wenn eine Bridge eine Socket-Verbindung herstellt, wird sie hier zwischengespeichert const clients = {} // Wenn ein Client eine Socket-Verbindung herstellt, wird sie hier zwischengespeichert. Die spezifische Datenstruktur finden Sie im Quellcode net.createServer(socket => { socket.on('Daten', Daten => { const request = data.toString() const url = request.match(/.+ (?<url>.+) /)?.groups?.url wenn (!url) zurückgeben wenn (isBridge(url)) { regesterBridge(Socket, URL) zurückkehren } const { bridge, key } = findBridge(Anfrage, URL) wenn (!bridge) return cacheClientRequest(Bridge, Schlüssel, Socket, Anfrage, URL) sendRequestToBridgeByKey(Schlüssel) }) }).listen(80) Schauen Sie sich die Code-Logik im Datenmonitor an:
Wenn Sie den Code und die Logik kombinieren, sollten Sie in der Lage sein, es zu verstehen, aber möglicherweise haben Sie Fragen zu 5. Lassen Sie uns diese nacheinander klären. Codeblock 2: isBridge Die Methode zur Bestimmung, ob es sich um eine Brückenregistrierungsanforderung handelt, ist sehr einfach. Für das reale Geschäft können jedoch genauere Daten definiert werden. Funktion isBridge (URL) { returniere url.startsWith('/regester?') } Codeblock drei: registerBridge Funktion regesterBridge (Socket, URL) { const Schlüssel = url.match(/(^|&|\?)Schlüssel=(?<Schlüssel>[^&]*)(&|$)/?.Gruppen?.Schlüssel Brücken[Schlüssel] = Sockel socket.removeAllListeners('Daten') }
Codeblock 4: findBridge Wenn die Logik Codeblock 4 erreicht, bedeutet dies, dass dies bereits eine Client-Anforderung ist. Dann muss zuerst die entsprechende Brücke gefunden werden. Wenn keine Brücke vorhanden ist, muss zuerst die Brücke registriert werden. Anschließend muss der Benutzer die Client-Anforderung initiieren. Der Code lautet wie folgt: Funktion findBridge (Anfrage, URL) { let Schlüssel = url.match(/\/(?<Schlüssel>[^\/\?]*)(\/|\?|$)/)?.Gruppen?.Schlüssel let bridge = Brücken [Schlüssel] if (Brücke) return { Brücke, Schlüssel } const referer = request.match(/\r\nReferer: (?<referer>.+)\r\n/?.groups?.referer wenn (!referer) return {} Schlüssel = Referrer.split('//')[1].split('/')[1] bridge = Brücken[Schlüssel] if (Brücke) return { Brücke, Schlüssel } zurückkehren {} }
Codeblock 5: cacheClientRequest Die Codeausführung hier zeigt an, dass es sich bereits um eine Client-Anforderung handelt. Wir cachen diese Anforderung zunächst. Beim Cachen cachen wir auch die der Anforderung entsprechende Bridge und Tastenkombinationen, um nachfolgende Vorgänge zu erleichtern. Warum Client-Anfragen zwischenspeichern? In der aktuellen Lösung hoffen wir, dass sowohl Anfragen als auch Antworten paarweise angeordnet sind. Wir wissen, dass die Netzwerkübertragung fragmentiert ist. Wenn wir derzeit die Anforderung und Antwort nicht paarweise und in der richtigen Reihenfolge auf der Anwendungsebene steuern, führt dies zu Verwirrung zwischen den Datenpaketen. Dies ist die aktuelle Situation. Wenn es später eine bessere Lösung gibt, können wir der TCP/IP-Schicht vertrauen, anstatt die Anforderung und Antwort der Daten in der Anwendungsschicht in der richtigen Reihenfolge zu erzwingen. Funktion cacheClientRequest (Bridge, Schlüssel, Socket, Anfrage, URL) { wenn (Kunden[Schlüssel]) { Clients[Schlüssel].Requests.push({Bridge, Schlüssel, Socket, Anfrage, URL}) } anders { Kunden[Schlüssel] = {} Clients[Schlüssel].Anfragen = [{Bridge, Schlüssel, Socket, Anfrage, URL}] } } Wir ermitteln zunächst, ob unter dem der Brücke entsprechenden Schlüssel bereits ein Client-Anforderungscache vorhanden ist. Wenn ja, fügen wir ihn ein. Wenn nicht, erstellen wir ein Objekt und initialisieren diese Anfrage. Der nächste Schritt ist der komplizierteste. Er besteht darin, den Anforderungscache zu entfernen, ihn an die Brücke zu senden und die Antwort der Brücke abzuhören, bis die aktuelle Antwort endet. Löschen Sie dann die Datenüberwachung der Brücke, versuchen Sie, die nächste Anforderung zu entfernen, und wiederholen Sie die obigen Aktionen, bis alle Anforderungen des Clients verarbeitet sind. Codeblock sechs: sendRequestToBridgeByKey Am Ende des fünften Codeblocks wird eine zusammenfassende Beschreibung des Blocks gegeben. Sie können es zunächst ein wenig verstehen und sich dann den folgenden Code ansehen, da der Code einige Beurteilungen der Antwortintegrität enthält. Wenn Sie diese entfernen, ist der Code leichter zu verstehen. In der gesamten Lösung haben wir die Anforderungsintegrität nicht verarbeitet, da eine Anforderung grundsätzlich die Größe eines Datenpakets hat, es sei denn, es handelt sich um eine Datei-Upload-Schnittstelle, die wir jetzt nicht verarbeiten werden. Andernfalls wird der Code komplizierter. Funktion sendRequestToBridgeByKey (Schlüssel) { const client = clients[Schlüssel] wenn (client.isSending) return const Anfragen = Client.Anfragen wenn (Anfragen.Länge <= 0) return client.isSending = true client.contentLength = 0 client.empfangen = 0 const {bridge, socket, request, url} = Anfragen.shift() const newUrl = url.replace(Schlüssel, '') const newRequest = request.replace(url, neueUrl) bridge.write(neueAnfrage) bridge.on('Daten', Daten => { const Antwort = data.toString() let code = response.match(/^HTTP[S]*\/[1-9].[0-9] (?<code>[0-9]{3}).*\r\n/?.groups?.code wenn (Code) { Code = parseInt(Code) wenn (Code === 200) { let contentLength = response.match(/\r\nInhaltslänge: (?<contentLength>.+)\r\n/?.groups?.contentLength if (Inhaltslänge) { Inhaltslänge = parseInt(Inhaltslänge) client.contentLength = Inhaltslänge Client.empfangen = Puffer.von(Antwort.split('\r\n\r\n')[1]).Länge } } anders { socket.schreiben(Daten) client.isSending = false bridge.removeAllListeners('Daten') sendRequestToBridgeByKey(Schlüssel) zurückkehren } } anders { Client.empfangen += Daten.Länge } socket.schreiben(Daten) wenn (Client.Inhaltslänge <= Client.Empfangen) { client.isSending = false bridge.removeAllListeners('Daten') sendRequestToBridgeByKey(Schlüssel) } }) } Nehmen Sie aus den Clients den Client heraus, der dem Bridge-Schlüssel entspricht.
An diesem Punkt ist die Kerncodelogik abgeschlossen. Zusammenfassen Nachdem Sie diesen Codesatz verstanden haben, können Sie ihn erweitern und den Code für Ihren eigenen Gebrauch bereichern. Können Sie sich nach dem Verständnis dieses Codesatzes andere Verwendungsszenarien dafür vorstellen? Kann diese Idee auch für die Fernsteuerung verwendet werden? Wenn Sie den Client steuern möchten, können Sie sich von diesem Code inspirieren lassen. ProxyServe-Quellcodeconst net = erfordern('net') const Brücken = {} const Kunden = {} net.createServer(socket => { socket.on('Daten', Daten => { const request = data.toString() const url = request.match(/.+ (?<url>.+) /)?.groups?.url wenn (!url) zurückgeben wenn (isBridge(url)) { regesterBridge(Socket, URL) zurückkehren } const { bridge, key } = findBridge(Anfrage, URL) wenn (!bridge) return cacheClientRequest(Bridge, Schlüssel, Socket, Anfrage, URL) sendRequestToBridgeByKey(Schlüssel) }) }).listen(80) Funktion isBridge (URL) { returniere url.startsWith('/regester?') } Funktion regesterBridge (Socket, URL) { const Schlüssel = url.match(/(^|&|\?)Schlüssel=(?<Schlüssel>[^&]*)(&|$)/?.Gruppen?.Schlüssel Brücken[Schlüssel] = Sockel socket.removeAllListeners('Daten') } Funktion findBridge (Anfrage, URL) { let Schlüssel = url.match(/\/(?<Schlüssel>[^\/\?]*)(\/|\?|$)/)?.Gruppen?.Schlüssel let bridge = Brücken [Schlüssel] if (Brücke) return { Brücke, Schlüssel } const referer = request.match(/\r\nReferer: (?<referer>.+)\r\n/?.groups?.referer wenn (!referer) return {} Schlüssel = Referrer.split('//')[1].split('/')[1] bridge = Brücken[Schlüssel] if (Brücke) return { Brücke, Schlüssel } zurückkehren {} } Funktion cacheClientRequest (Bridge, Schlüssel, Socket, Anfrage, URL) { wenn (Kunden[Schlüssel]) { Clients[Schlüssel].Requests.Push({Bridge, Schlüssel, Socket, Anfrage, URL}) } anders { Kunden[Schlüssel] = {} Clients[Schlüssel].Anfragen = [{Bridge, Schlüssel, Socket, Anfrage, URL}] } } Funktion sendRequestToBridgeByKey (Schlüssel) { const client = clients[Schlüssel] wenn (client.isSending) return const Anfragen = Client.Anfragen if (Anfragen.Länge <= 0) return client.isSending = true client.contentLength = 0 client.empfangen = 0 const {bridge, socket, request, url} = Anfragen.shift() const newUrl = url.replace(Schlüssel, '') const newRequest = request.replace(url, neueUrl) bridge.write(neueAnfrage) bridge.on('Daten', Daten => { const Antwort = data.toString() let code = response.match(/^HTTP[S]*\/[1-9].[0-9] (?<code>[0-9]{3}).*\r\n/?.groups?.code wenn (Code) { Code = parseInt(Code) wenn (Code === 200) { let contentLength = response.match(/\r\nInhaltslänge: (?<contentLength>.+)\r\n/?.groups?.contentLength if (Inhaltslänge) { Inhaltslänge = parseInt(Inhaltslänge) client.contentLength = Inhaltslänge Client.empfangen = Puffer.von(Antwort.split('\r\n\r\n')[1]).Länge } } anders { socket.schreiben(Daten) client.isSending = false bridge.removeAllListeners('Daten') sendRequestToBridgeByKey(Schlüssel) zurückkehren } } anders { Client.empfangen += Daten.Länge } socket.schreiben(Daten) wenn (Client.Inhaltslänge <= Client.Empfangen) { client.isSending = false bridge.removeAllListeners('Daten') sendRequestToBridgeByKey(Schlüssel) } }) } Dies ist das Ende dieses Artikels über die Implementierung des Intranet-Penetrationsdienstes durch Nodejs. Weitere relevante Inhalte zur Intranet-Penetration von Node finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Grafisches Tutorial zur Installation und Konfiguration von MySQL Server 5.7.20
>>: Detaillierte Erläuterung der Bereitstellung von MySQL mit Docker (Datenpersistenz)
1. Rufen Sie die offizielle Docker-Website auf Ge...
Suchseite: search.wxml-Seite: <view class=&quo...
Einführung: Die Nachteile der Speicherung aller D...
In diesem Artikel wird der spezifische Code von J...
1. Liste Der Listen-UL- Container wird mit einer ...
vue implementiert die Drag & Drop-Sortierfunk...
1. Ziehen Sie das Bild Docker-Pull-Registrierung....
So schreiben Sie DROP TABLE in verschiedene Daten...
1. Erstellen Sie eine Repo-Datei Lesen Sie die of...
Ich frage mich, ob Sie jemals über diese Frage na...
Linux wird im Allgemeinen als Server verwendet un...
Im Linux-System gibt es einen Dateityp namens Lin...
Zuvor habe ich mehrere Möglichkeiten vorgestellt,...
Inhaltsverzeichnis 1. Einführung in PXC 1.1 Einfü...
Vorwort Ab MySQL 5.7.11 unterstützt MySQL die Dat...