Skip to content

Instantly share code, notes, and snippets.

@stolsma

stolsma/test.js

Created Aug 25, 2012
Embed
What would you like to do?
Lower worker privilege with cluster or fork when run as root and still able to use unprivilaged ports
var cluster = require('cluster');
var util = require('util');
var http = require('http');
var numCPUs = 2; //require('os').cpus().length;
//
// general functions
//
function isRoot() {
return process.getuid() == 0;
}
//
// Check args
//
var runUser = process.argv[2],
runGroup = process.argv[3] || runUser;
if (isRoot() && !runUser) {
console.log('When runned as root a user needs to be given as argument!');
process.exit(1);
}
//
// The real deal....
//
if (cluster.isMaster) {
cluster.on('online', function(worker) {
console.log("Yay, the worker responded after it was forked: ", worker.process.pid);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
cluster.on('listening', function(worker, listenData) {
console.log('worker ' + worker.process.pid + ' is listening on: ' + util.inspect(listenData));
});
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
// drop privileges to normal user if root
if (isRoot()) {
process.setgid(runUser);
process.setuid(runGroup);
}
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world from process:" + process.pid + "\n");
}).listen(80);
}
var fork = require('child_process').fork;
var util = require('util');
var http = require('http');
var net = require('net');
var numCPUs = 2; //require('os').cpus().length;
//
// general functions
//
function isRoot() {
return process.getuid() == 0;
}
function isObject(o) {
return (typeof o === 'object' && o !== null);
}
function toDecInt(value) {
value = parseInt(value, 10);
return isNaN(value) ? null : value;
}
//
// Check args
//
var runUser = process.argv[2] || proces.getuid,
runGroup = process.argv[3] || runUser;
if (isRoot() && !runUser) {
console.log('When runned as root a user needs to be given as argument!');
process.exit(1);
}
var isWorker = 'TEST_WORKER' in process.env,
isMaster = !isWorker;
var serverHandlers = {};
function forkChild(customEnv) {
var child,
options = {},
self = this,
env = process.env;
// Create env object
// first: copy and add id property
var envCopy = util._extend({}, env);
envCopy['TEST_WORKER'] = 'WORKER';
// second: extend envCopy with the env argument
if (isObject(customEnv)) {
envCopy = util._extend(envCopy, customEnv);
}
// fork child
child = fork(process.argv[1], process.argv.slice(2), {
'env': envCopy,
'silent': false,
'execArgv': process.execArgv,
'uid': toDecInt(runUser),
'gid': toDecInt(runGroup)
});
// proces child message
child.on('message', function (message) {
// This sequence of information is unique to the connection
// but not to the worker
var args = [message.address,
message.port,
message.addressType,
message.fd];
var key = args.join(':');
var handler;
if (serverHandlers.hasOwnProperty(key)) {
handler = serverHandlers[key];
} else {
handler = serverHandlers[key] = net._createServerHandle.apply(net, args);
}
// echo callback with the fd handler associated with it
child.send({}, handler);
console.log('worker ' + message.pid + ' is listening on: ' + util.inspect(message));
});
child.on('error', function () {
console.error(arguments);
});
return child;
}
//
// The real deal....
//
if (isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
forkChild();
}
} else {
// Get a handle bound to the socket we want to use
var options = {
pid: process.pid,
address: '0.0.0.0',
port: 80,
addressType: 4,
fd: null
}
process.send(options);
process.on('message', function (message, handler) {
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
console.log('Request on worker with pid: ' + process.pid);
res.writeHead(200);
res.end("hello world from process:" + process.pid + "\n");
}).listen(handler);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment