is there any possibility to create a https server on top of a existing tls.Server?
The documentation says: "This class is a subclass of tls.Server..".
I want to use the tls.Server to work with the pure data stream and if needed let the https server handle the rest. (Like express with https, just on a lower layer)
Regards
There isn't any official/supported way for that.
However if you look at the source code of https server, it's just a glue that connects together TLS server and HTTP connection handler:
function Server(opts, requestListener) {
if (!(this instanceof Server)) return new Server(opts, requestListener);
if (process.features.tls_npn && !opts.NPNProtocols) {
opts.NPNProtocols = ['http/1.1', 'http/1.0'];
}
/// This is the part where we instruct TLS server to use
/// HTTP code to handle incoming connections.
tls.Server.call(this, opts, http._connectionListener);
this.httpAllowHalfOpen = false;
if (requestListener) {
this.addListener('request', requestListener);
}
this.addListener('clientError', function(err, conn) {
conn.destroy();
});
this.timeout = 2 * 60 * 1000;
}
To switch to HTTPS in your TLS connection handler, you could do something along these lines:
var http = require('http');
function myTlsRequestListener(cleartextStream) {
if (shouldSwitchToHttps) {
http._connectionListener(cleartextStream);
} else {
// do other stuff
}
}
The code above is based on version 0.11 (i.e. current master).
WARNING
Using internal Node API might bite you during upgrade to a newer version (i.e. your application might stop working after upgrade).
Related
I am using solutions provided in following topics to inspect WebSockets traffic (messages) on the web page, which I do not own (solely for learning purposes):
Inspecting WebSocket frames in an undetectable way
Listening to a WebSocket connection through prototypes
https://gist.github.com/maskit/2252422
Like this:
(function(){
var ws = window.WebSocket;
window.WebSocket = function (a, b, c) {
var that = c ? new ws(a, b, c) : b ? new ws(a, b) : new ws(a);
that.addEventListener('open', console.info.bind(console, 'socket open'));
that.addEventListener('close', console.info.bind(console, 'socket close'));
that.addEventListener('message', console.info.bind(console, 'socket msg'));
return that;
};
window.WebSocket.prototype=ws.prototype;
}());
The issue with the provided solutions is that they are listening on only 1 of 3 WebSocket connections ("wss://..."). I am able to see in the console the messages that I receive or send, but only for one connection.. Is there something I am missing? Is it possible that two other service are any different and prohibiting the use of prototype extension technique?
p.s. I will not provide an URL to the web resource that I am doing my tests on, in order to avoid possible bans or legal questions.
Okay, since it's been weeks and no answers, then I will post a solution which I ended up using.
I have built my own Chrome extension that listens to WebSocket connections and forwards all requests and responses to my own WebSocket server (which I happen to run in C#).
There are some limitations to this approach. You are not seeing the request header or who is sending the packets.. You are only able to see the payload and that is it. Also you are not able to modify the contents in any way or send your own requests (remember - you have no access to header metadata). Naturally, another limitation is that you have to be running Chrome (devtools APIs are used)..
Some instructions.
Here is how you attach debugger to listen to network packets:
chrome.debugger.attach({ tabId: tabId }, "1.2", function () {
chrome.debugger.sendCommand({ tabId: tabId }, "Network.enable");
chrome.debugger.onEvent.addListener(onTabDebuggerEvent);
});
Here is how you catch them:
function onTabDebuggerEvent(debuggeeId, message, params) {
var debugeeTabId = debuggeeId.tabId;
chrome.tabs.get(debugeeTabId, function (targetTab) {
var tabUrl = targetTab.url;
if (message == "Network.webSocketFrameSent") {
}
else if (message == "Network.webSocketFrameReceived") {
var payloadData = params.response.payloadData;
var request = {
source: tabUrl,
payload: params.response.payloadData
};
websocket.send(JSON.stringify(request));
}
});
}
Here is how you create a websocket client:
var websocket = new WebSocket("ws://127.0.0.1:13529");
setTimeout(() => {
if (websocket.readyState !== 1) {
console.log("Unable to connect to a WebsocketServer.");
websocket = null;
}
else {
console.log("WebsocketConnection started", websocket);
websocket.onclose = function (evt) {
console.log("WebSocket connection got closed!");
if (evt.code == 3001) {
console.log('ws closed');
} else {
console.log('ws connection error');
}
websocket = null;
};
websocket.onerror = function (evt) {
console.log('ws normal error: ' + evt.type);
websocket = null;
};
}
}, 3000);
Creating the server is outside the scope of this question. You can use one in Node.js, C# or Java, whatever is preferable for you..
This is certainly not the most convenient approach, but unlike java-script injection method - it works in all cases.
Edit: totally forgot to mention. There seems to be another way of solving this, BUT I have not dig into that topic therefore maybe this is false info in some way. It should be possible to catch packets on a network interface level, through packet sniffing utilities. Such as Wireshark or pcap. Maybe something I will investigate further in the future :)
Scenario
C# Based Server
JavaScript Based Client
Situation
I created this fairly simple "server" which only job is to help me understanding how to actually use those websockets in a C# environment.
using (var server = new HttpListener())
{
server.Prefixes.Add("http://localhost:8080/");
server.Start();
while(true)
{
var context = server.GetContext();
if (context.Request.IsWebSocketRequest)
{
var cntxt = context.AcceptWebSocketAsync(null).ConfigureAwait(true).GetAwaiter().GetResult();
var buff = new byte[2048];
while(cntxt.WebSocket.State == System.Net.WebSockets.WebSocketState.Open || cntxt.WebSocket.State == System.Net.WebSockets.WebSocketState.Connecting)
{
cntxt.WebSocket.ReceiveAsync(new ArraySegment<byte>(buff), CancellationToken.None).ConfigureAwait(true).GetAwaiter().GetResult();
Console.WriteLine(Encoding.UTF8.GetString(buff));
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
using (var writer = new StreamWriter(context.Response.OutputStream))
{
writer.Write("<html><body>WEBSOCKET ONLY!</body></html>");
}
}
}
}
The problem now is: when i try to add the websocket prefix via server.Prefixes.Add("ws://localhost:8080"), i get some System.ArgumentException thrown which tells my i can only add http and https as accepted protocol.
Thing is: doing it and using ws = new WebSocket('ws://localhost:8080'); (JavaScript) to connect to a websocket, yields for obvious reasons nothing.
Changing the prefix to HTTP in the JS websocket, will provide me with yet another sort-off argument exception.
Actual Question
how to actually get the HttpListener to acceppt web socket requests?
Further Info
Used .net framework is 4.6.1
Browser to test this was Google Chrome 69.0.3497.100
The reason for why the above was not working ... is due to the JS websocket requiring a path.
Changing the above HttpListener prefix to eg. "http://localhost:8080/asdasd/" will allow the socket to connect propertly.
I decided that i want to investigate what is the best possible way to handle big amount of traffic with NodeJS server, i did a small test on 2 digital ocean servers which has 1GB RAM / 2 CPUs
No-Cluster server code:
// Include Express
var express = require('express');
// Create a new Express application
var app = express();
// Add a basic route – index page
app.get('/', function (req, res) {
res.redirect('http://www.google.co.il');
});
// Bind to a port
app.listen(3000);
console.log('Application running');
Cluster server code:
// Include the cluster module
var cluster = require('cluster');
// Code to run if we're in the master process
if (cluster.isMaster) {
// Count the machine's CPUs
var cpuCount = require('os').cpus().length;
// Create a worker for each CPU
for (var i = 0; i < cpuCount; i += 1) {
cluster.fork();
}
// Code to run if we're in a worker process
} else {
// Include Express
var express = require('express');
// Create a new Express application
var app = express();
// Add a basic route – index page
app.get('/', function (req, res) {
res.redirect('http://www.walla.co.il');
});
// Bind to a port
app.listen(3001);
console.log('Application running #' + cluster.worker.id);
}
And i sent stress test requests to those servers, i excepted that the cluster server will handle more requests but it didn't happen, both servers crashed on the same load, although 2 node services were running on the cluster and 1 service on the non-cluster.
Now i wonder why ? Did i do anything wrong?
Maybe something else is making the servers reach its breakpoint? both servers crashed at ~800 rps
Now i wonder why ? did i do anything wrong?
Your test server doesn't do anything other than a res.redirect(). If your request handlers use essentially no CPU, then you aren't going to be CPU bound at all and you won't benefit from involving more CPUs. Your cluster will be bottlenecked at the handling of incoming connections which is going to be roughly the same with or without clustering.
Now, add some significant CPU usage to your request handler and you should get a different result.
For example, change to this:
// Add a basic route – index page
app.get('/', function (req, res) {
// spin CPU for 200ms to simulate using some CPU in the request handler
let start = Date.now();
while (Date.now() - start < 200) {}
res.redirect('http://www.walla.co.il');
});
Running tests is a great thing, but you have to be careful what exactly you're testing.
What #jfriend00 says is correct; you aren't actually doing enough heavy lifting to justify this, however, you're not actually sharing the load. See here:
app.listen(3001);
You can't bind two services onto the same port and have the OS magically load-balance them[1]; try adding an error handler on app.listen() and see if you get an error, e.g.
app.listen(3001, (err) => err ? console.error(err));
If you want to do this, you'll have to accept everything in your master, then instruct the workers to do the task, then pass the results back to the master again.
It's generally easier not to do this in your Node program though; your frontend will still be the limiting factor. An easier (and faster) way may be to put a special purpose load-balancer in front of multiple running instances of your application (i.e. HAProxy or Nginx).
[1]: That's actually a lie; sorry. You can do this by specifying SO_REUSEPORT when doing the initial bind call, but you can't explicitly specify that in Node, and Node doesn't specify it for you...so you can't in Node.
On the iOS clients, I'm using SocketRocket by Square: https://github.com/square/SocketRocket
Everywhere I have looked, I have found comparisons of Websocket libraries based on web applications accessed from browser, or queried in a database, but nothing as yet for clients that are iOS smartphone apps.
The clients would connect to the remote server on request through the app (i.e. the connection isn't "always-on" or done through a mobile browser or proxy or GameCenter), and, once connected, be paired with other clients in a two-player "game" situation. Until a match ends, the connection would need to persist, and the server would be responsible for timing each user's turn and receiving & issuing commands from/to each user, sort of like a turn-based game except each turn has a server-managed time limit. After a match ends (generally 15-20 minutes), if a user doesn't want another match with another random opponent, then the connection would be closed and the user logged off; users that want to continue would then be matched with another user by the hosting server (running Node.js and the Websocket library).
Some of the options I have considered include
Socket.IO 1.0: http://socket.io/
Sockjs: https://github.com/sockjs
ws: https://github.com/einaros/ws
nodejs-websocket: https://www.npmjs.com/package/nodejs-websocket
but heard from https://medium.com/#denizozger/finding-the-right-node-js-websocket-implementation-b63bfca0539 that Socket.IO isn't optimal for heavy user traffic (and I'm anticipating more than 300 users requesting matches at any one point), and that Sockjs doesn't have some command query feature, but didn't quite find a conclusive answer in the context of smartphones or iOS devices -- not browsers -- either way, in any situation.
The question is what Node.js server Websocket library might play nicest or interface with the fewest stability/scalability/complexity concerns with the iOS clients running SocketRocket? The SocketRocket wiki itself isn't helpful as it uses a Python/Go-based server side test.
EDIT: Potentially helpful resource:
http://www.teehanlax.com/blog/how-to-socket-io-swift/
Only missing thing is a comparison or discussion of other potential websocket APIs, not just Socket.IO. But this is a start in that it seems to be working with the latest iOS, SocketRocket, and Socket.IO builds.
I like Sockjs because it is simple. Here is an implementation for SocketRocket --> Sockjs that works as proof of concept
NEED:
-SocketRocket (add libicucore.dylib, Security.framework and CFNetwork.framework to your project)
-Node.js
-Sockjs Server
SERVER:
var http = require('http'),
sockjs = require('sockjs'),
sockserver = sockjs.createServer(),
connections = [];
sockserver.on('connection', function(conn) {
console.log('Connected');
connections.push(conn);
conn.on('data', function(message) {
console.log('Message: ' + message);
// send the message to all clients
for (var i=0; i < connections.length; ++i) {
connections[i].write(message);
}
//
});
conn.on('close', function() {
connections.splice(connections.indexOf(conn), 1); // remove the connection
console.log('Disconnected');
});
});
var server = http.createServer();
sockserver.installHandlers(server, {prefix:'/sockserver'});
server.listen(3000, '0.0.0.0'); // http://localhost:3000/sockserver/websocket
CLIENT (ViewController.m):
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
{
SRWebSocket *myWebSocket;
__weak IBOutlet UILabel *connectionStatus;
__weak IBOutlet UITextView *myTextView;
}
- (void)viewDidLoad {
[super viewDidLoad];
connectionStatus.textColor = [UIColor redColor];
myWebSocket = [[SRWebSocket alloc] initWithURL:[[NSURL alloc] initWithString:#"http://localhost:3000/sockserver/websocket"]];
myWebSocket.delegate = self;
[myWebSocket open];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
myTextView.text = message;
NSLog(#"message: %#",message);
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
connectionStatus.text = #"Disconnected";
connectionStatus.textColor = [UIColor redColor];
}
- (void)webSocketDidOpen:(SRWebSocket *)webSocket{
connectionStatus.text = #"Connected";
connectionStatus.textColor = [UIColor greenColor];
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
}
#end
src: http://nunoferro.pt/?p=22
I can't find any information on this and I was wondering if this was even possible?
I have a Minecraft server that I want to ping to find out if it is on at a specific port. I want to do this in Javascript but from what I can see that you cant really do that or it hasn't been done before. Are there any plugins or 3rd party Javascript vendors that can accomplish this?
For example:
mc.mydomain.net:25565
Javascript pings the server and it changes the text from online to offline, depending on if it can connect.
Server is: Online
Or
Server is: Offline
If it happened that the Minecraft server actually speak plains HTTP on that port (which is unlikely), then it could work.
Otherwise, no, it can't be done, at least not with current specifications.
Browsers can only talk HTTP (i.e. to web servers) and WebSockets, and the SSL variants thereof. I don't know whether the upcoming WebRTC protocol would help.
The alternative is to use Flash - AIUI that has a plain TCP socket capability that can be exposed to JS code that might help in these circumstances.
First of all you can't ping ports, as Ping is using ICMP which doesn't have the concept of ports. Ports belong to the transport layer protocols like TCP and UDP.
So, a solution can be the use of a server side language like PHP to perform the query and then you can make an AJAX request to this page in order to retrieve the result. Here is an example in PHP:
<?php
error_reporting(E_ERROR);
$fp = fsockopen('mc.mydomain.net', 25565, $errno, $errstr, 1);
if (!$fp) {
echo 'no';
} else {
echo 'yes';
fclose($fp);
}
?>
Moreover, to keep your requests fast, you can imagine to cache the result of the above query into a file or a database and refresh its value every couple of minutes (for example by using a cron job) and then serve the cached result to the AJAX request.
From http://www.gnucitizen.org/static/blog/2006/08/jsportscanner.js , the first hit when you search for "javascript portscan":
var AttackAPI = {
version: '0.1',
author: 'Petko Petkov (architect)',
homepage: 'http://www.gnucitizen.org'};
AttackAPI.PortScanner = {};
AttackAPI.PortScanner.scanPort = function (callback, target, port, timeout) {
var timeout = (timeout == null)?100:timeout;
var img = new Image();
img.onerror = function () {
if (!img) return;
img = undefined;
callback(target, port, 'open');
};
img.onload = img.onerror;
img.src = 'http://' + target + ':' + port;
setTimeout(function () {
if (!img) return;
img = undefined;
callback(target, port, 'closed');
}, timeout);
};
AttackAPI.PortScanner.scanTarget = function (callback, target, ports, timeout)
{
for (index = 0; index < ports.length; index++)
AttackAPI.PortScanner.scanPort(callback, target, ports[index], timeout);
};
You can only send HTTP(S) or WS(S) request to the domain you are on with JavaScript. A Ping is much too low-level.
If the minecraft server supports HTTP, you can try to use that.