Current xinetd functionality allows you to start a server at the level of a connection but it is limited to only servicing that connection. Apache 1.3 (configured with ‘ServerType inetd’) can be run by xinetd this way quite effectively however it is exec’d for each connection. For this experiment I’m using RHEL6 with selinux-policy-mls installed and to keep it simple I’m running SELinux in permissive mode. Configuration of labeled networking was accomplished as follows:
1. Create a CIPSO DOI so that the system can understand packets (both inbound and outbound) that have a CIPSO DOI of "2". # netlabelctl cipsov4 add local doi:2 2. In this example we are going to use address selectors to ensure we only send CIPSO "local" traffic to localhost so we need to delete the existing legacy domain selector and re-create it with the address selectors: # netlabelctl map del default # netlabelctl map add default address:0.0.0.0/0 protocol:unlbl 3. We need to tell the system that for all the packets destined for localhost we want to assign CIPSO tags/labels using DOI "2": # netlabelctl map add default address:127.0.0.1 protocol:cipsov4,2
node-webworker by Peter Griess is utilized to implement a super servers that runs servers at level that can process multiple connection and my node-selinux module for doing SELinux stuff.
The master:
var path = require('path');
var Worker = require('webworker/webworker').Worker;
var sys = require('sys');
var net = require('net');
var selinux = require('selinux_node');
var workers = new Array();
var s = new selinux.SELinux();
var srv = net.createServer(function (stream) {
stream.pause();
sys.puts("connection " + stream.fd);
s.getpeercon(stream.fd, function (con) {
var w;
if (typeof(workers[con]) == 'undefined') {
sys.puts("create new worker for context " + con);
s.setexeccon(con);
w = new Worker(path.join(__dirname, 'xworker.js'));
workers[con] = w;
}
else {
w = workers[con];
sys.puts("use existing worker ", w);
}
w.postMessage({ 'banner' : 'Hello, world!' }, stream.fd);
}
);
}).listen(5000, "127.0.0.1");
The worker:
var assert = require('assert');
var http = require('http');
var sys = require('sys');
var net = require('net');
var banner = undefined;
var srv = http.createServer(function(req, resp) {
resp.writeHead(200, {'Content-Type' : 'text/plain'});
resp.write(banner + ' (pid ' + process.pid + ')\n');
resp.end();
});
onmessage = function(msg) {
assert.ok(msg.fd && msg.fd > 0);
sys.print('Got message!\n');
banner = msg.data.banner;
var s = new net.Stream(msg.fd);
s.type = srv.type;
s.server = srv;
s.resume();
srv.emit('connection', s);
};
Test can be done simply by using curl and newrole for example:
curl http://127.0.0.1:5000
To test at different levels run:
newrole -l s0-s0 -- -c "curl http://127.0.0.1:5000"
Server test output:
[tedx@localhost ~]$ node fdmaster.js connection 6 create new worker for context staff_u:staff_r:staff_t:SystemLow-SystemHigh Got message! connection 9 create new worker for context staff_u:staff_r:staff_t:SystemLow Got message! connection 12 create new worker for context staff_u:staff_r:staff_t:UNCLASSIFIED Got message! connection 15 use existing worker [object Object] Got message!
Test run output:
[tedx@localhost ~]$ curl http://127.0.0.1:5000 Hello, world! (pid 23425) [tedx@localhost ~]$ newrole -l s0-s0 -- -c "curl http://127.0.0.1:5000" Password: Hello, world! (pid 23476) [tedx@localhost ~]$ newrole -l s1-s1 -- -c "curl http://127.0.0.1:5000" Password: Hello, world! (pid 23530) [tedx@localhost ~]$ newrole -l s1-s1 -- -c "curl http://127.0.0.1:5000" Password: Hello, world! (pid 23530)
Notice that the last two requests went to the same child.
What’s missing you ask, policy! The dirty little secret of SELinux is policy which I’ve totally ignored in this example. If you were to create a unique SELinux type for your worker you’d probably do this by creating a script that wraps node and assign it a file context and you’d write policy to transition from the file context to your workers unique context. Luckily the webworker constructor can handle this by allowing you to specify the node command to use when running the worker script.
w = new Worker(path.join(__dirname, 'xworker.js'), {'path' : '/usr/local/bin/node-my-unique-selinux-type'});
Comments are closed.