Created
August 25, 2012 13:42
-
-
Save stolsma/3465889 to your computer and use it in GitHub Desktop.
Lower worker privilege with cluster or fork when run as root and still able to use unprivilaged ports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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