direct (non-tcp) connection to redis from nodejs - node.js

hello all
I looked at the at the redis-node-client source (relevant part is shown bellow) and I see that it connects to redis via the 'net' package, which is TCP based.
line 370
exports.createClient = function (port, host, options) {
var port = port || exports.DEFAULT_PORT;
var host = host || exports.DEFAULT_HOST;
var client = new Client(net.createConnection(port, host), options);
client.port = port;
client.host = host;
return client;
};
I was wondering if there's a more direct client for redis, preferably via domain-sockets or something of that sort. Im using redis localy, as cache, without going over the wire so its unnecessary to encode/decode messages with TCP headers...
thank you

Unix Domain Socket support appears to have landed in Redis as of Nov 4th.
http://code.google.com/p/redis/issues/detail?id=231
To connect to a Unix Domain Socket, you need to supply the pathname to net.createConnection. Maybe something like this in redis-node-client:
exports.createSocketClient = function (path, options) {
var client = new Client(net.createConnection(path), options);
client.path = path;
return client;
};

Related

SMPP server - How to get the client (ESME's) IP address?

I'm using https://github.com/farhadi/node-smpp in order to create a smpp server.
I'm going to forbid connection if the client's IP address is not in the allowed ips list. For that when a new connection is open I have to check if the credentials are ok and if the IP address is a good one.
The question is how and where can I get the client (ESME's) IP address?
session.on('bind_transceiver', function(pdu) {
session.pause();
const username = pdu.system_id;
const password = pdu.password;
const ipAddress = ''; // WHERE TO GET IT??
if (credentialsAreOk(username, password, ipAddress)) {
session.send(pdu.response());
session.resume();
} else {
session.close();
}
});
When an ESME is connecting to your server, a session is created.
The network socket used by this TCP connection, which is a net.Socket class (https://nodejs.org/api/net.html#net_class_net_socket), is stored inside this session in the socket property.
const socket = session.socket;
So you can easily access this socket property of the session and get the remoteAddress (the clients IP) from there (https://nodejs.org/api/net.html#net_socket_remoteaddress).
const ipAddress = session.socket.remoteAddress;

Client side multiplexing using thrift in nodejs

How to implement client side multiplexing using thrift in nodejs?
I tried the below code, but in vain.
var transport = thrift.TBufferedTransport;
var protocol = thrift.TBinaryProtocol;
var multiplexer = thrift.Multiplexer;
var ip = 'localhost';
var port = 9090;
var connection = thrift.createConnection(ip, port, {
transport : transport,
protocol : protocol
});
multiplexer();
var client = multiplexer.prototype.createClient(
"myServiceName", myServiceClient, connection
);
When I use the above client and call a method/function that is defined in my service,
connection is being made smoothly (no connection error) and
service method/function runs smoothly and returns the output.
But upon receiving the data (buffered) connection.js in thrift npm module throws "Cannot set property '0' of undefined" error.
On further investigation I found that seqid which is set on each client creation, is not being set.
Can someone please help me on this?
I found this to be the solution for the client:
var transport = thrift.TBufferedTransport;
var protocol = thrift.TBinaryProtocol;
var multiplexer = thrift.Multiplexer;
var ip = 'localhost';
var port = 9090;
var connection = thrift.createConnection(ip, port, {
transport : transport,
protocol : protocol
});
var multiplexer = new thrift.Multiplexer();
var client = multiplexer.createClient(
"myServiceName", myServiceClient, connection
);

How to create a MySQL adapter for session.io in NodeJS?

I have a NodeJS project on 2 Google Cloud instances behind a load-balancer. I'm using socket.io. I want to share the sessions between the instances.
Usually developers doing it using socket.io-redies, but I don't want redis just for that. I have Cloud SQL (Aka: MySQL), and I want to use MySQL for sharing the sessions.
I have understand the whole index.js of the redis adapter file, except this function:
https://github.com/socketio/socket.io-redis/blob/master/index.js#L93
Redis.prototype.onmessage = function(channel, msg){
var args = msgpack.decode(msg);
var packet;
if (uid == args.shift()) return debug('ignore same uid');
packet = args[0];
if (packet && packet.nsp === undefined) {
packet.nsp = '/';
}
if (!packet || packet.nsp != this.nsp.name) {
return debug('ignore different namespace');
}
args.push(true);
this.broadcast.apply(this, args);
};
If I need to get events from the MySQL (subscribe) I think it is not possible. Am I right?
Do you know another solution of sharing socket.io between two machines, without using Redis?

NodeJS STARTTLS Use SNI

I'm building a simple, STARTTLS capable POP3 Proxy in Node.JS and I'm having quite a hard time.
The proxy serves as a front-end for many back-end servers, so it must load their certificates dynamically, depending on the Client's connection.
I'm trying to use the SNICallback, which brings me the servername the client uses, but I can't set the right certificate after this, because I need one certificate before I have this call, when I create the secure context.
The code is as bellow:
// Load libraries
var net = require('net');
var tls = require('tls');
var fs = require('fs');
// Load certificates (created with openssl)
var certs = [];
for (var i = 1; i <= 8; i++) {
var hostName = 'localhost' + i;
certs[hostName] = {
key : fs.readFileSync('./private-key.pem'),
cert : fs.readFileSync('./public-cert' + i + '.pem'),
}
}
var server = net.createServer(function(socket) {
socket.write('+OK localhost POP3 Proxy Ready\r\n');
socket.on('data', function(data) {
if (data == "STLS\r\n") {
socket.write("+OK begin TLS negotiation\r\n");
upgradeSocket(socket);
} else if (data == "QUIT\r\n") {
socket.write("+OK Logging out.\r\n");
socket.end();
} else {
socket.write("-ERR unknown command.\r\n");
}
});
}).listen(10110);
and upgradeSocket() is as follows:
function upgradeSocket(socket) {
// I need this 'details' or handshake will fail with a message:
// SSL routines:ssl3_get_client_hello:no shared cipher
var details = {
key : fs.readFileSync('./private-key.pem'),
cert : fs.readFileSync('./public-cert1.pem'),
}
var options = {
isServer : true,
server : server,
SNICallback : function(serverName) {
return tls.createSecureContext(certs[serverName]);
},
}
sslcontext = tls.createSecureContext(details);
pair = tls.createSecurePair(sslcontext, true, false, false, options);
pair.encrypted.pipe(socket);
socket.pipe(pair.encrypted);
pair.fd = socket.fd;
pair.on("secure", function() {
console.log("TLS connection secured");
});
}
It handshakes correctly but the certificate I use is the static one in 'details', not the one I get in the SNICallback.
To test it I'm running the server and using gnutls-cli as a Client:
~$ gnutls-cli -V -s -p 10110 --crlf --insecure -d 5 localhost3
STLS
^D (Control+D)
The above command is supposed to get me the 'localhost3' certificate but it's getting the 'localhost1' because it's defined in 'details' var;
There are just too many examples throughout the internet with HTTPS or for TLS Clients, which it's a lot different from what I have here, and even for Servers as well but they're not using SNI. Any help will be appreciated.
Thanks in advance.
The answer is quite simple using tls.TLSSocket, though there is a gotcha with the listeners.
You have to remove all the listeners from the regular net.Socket you have, instantiate a new tls.TLSSocket using your net.Socket and put the listeners back on the tls.TLSSocket.
To achieve this easily, use a wrapper like Haraka's tls_socket pluggableStream over the regular net.Socket and replace the "upgrade"
function to something like:
pluggableStream.prototype.upgrade = function(options) {
var self = this;
var socket = self;
var netSocket = self.targetsocket;
socket.clean();
var secureContext = tls.createSecureContext(options)
var tlsSocket = new tls.TLSSocket(netSocket, {
// ...
secureContext : secureContext,
SNICallback : options.SNICallback
// ...
});
self.attach(tlsSocket);
}
and your options object would have the SNICallback defined as:
var options {
// ...
SNICallback : function(serverName, callback){
callback(null, tls.createSecureContext(getCertificateFor(serverName));
// ...
}
}

node net.createServer get connection path

Trying to cluster Socket.io using net.createServer. All examples are using IP to split what connection goes to witch node. However I'm using 4 servers with a load balancer that points ip;s to the different servers.
So in node cluster I would like to use an unique id to point the connection to a specific cluster.
Figure that each user that wants to connect can add a parameter to the connection url ws://localhost/socket.io?id=xxyyzz
How can I get the connection url in net.createServer
todays code for ip:
var server = net.createServer({ pauseOnConnect: true }, function(connection) {
// We received a connection and need to pass it to the appropriate
// worker. Get the worker for this connection's source IP and pass
// it the connection.
var remote = connection.remoteAddress;
var local = connection.localAddress;
var ip = (remote+local).match( /[0-9]+/g )[0].replace(/,/g, '');
var wIndex = ip % num_processes;
var worker = workers[wIndex];
worker.send('sticky-session:connection', connection);
});

Resources