// Baseline const product = 'NetRadius'; const version = '0.4.0'; // Load dependencies const dgram = require ('dgram'); const fs = require ('fs'); const http = require ('http'); // Load modules log = require ('./lib/logger.js'); const handlers = require ('./lib/handlers.js'); // Load configuration log.write (product + ' v' + version); config = { ports: {} }; config.ports.radius_authentication = process.env['SINATRA_PORT_RADIUS_AUTH'] || 1812; config.ports.radius_accounting = process.env['SINATRA_PORT_RADIUS_ACCT'] || 1813; config.ports.api = process.env['SINATRA_PORT_API'] || 8088; config.storage = process.env['SINATRA_STORAGE'] || "json:./data.json"; config.client_secret = process.env['SINATRA_CLIENT_SECRET'] || "password"; config.default_vlan = process.env['SINATRA_DEFAULT_VLAN'] || false; config.mac_auth_only = process.env['SINATRA_MAC_AUTH_ONLY'] || false; config.session_duration = process.env['SINATRA_SESSION_DURATION'] || 600; config.time_rules = process.env['SINATRA_TIME_RULES'] || false; // Display active configuration log.write ('Using configuration: ' + JSON.stringify (config)); // Listeners var listeners = { authentication: { socket: dgram.createSocket ({ type: 'udp4', reuseAddr: true }), handler: handlers.radius.authentication }, accounting: { socket: dgram.createSocket ({ type: 'udp4', reuseAddr: true }), handler: handlers.radius.accounting } }; // RADIUS authentication listeners.authentication.socket.on ('message', (msg, rinfo) => { handlers.radius.authentication (msg, rinfo, (response, err) => { if (!err) { listeners.authentication.socket.send (response, 0, response.length, rinfo.port, rinfo.address, function (err, bytes) { if (err) { console.log ('Error sending response to ', rinfo); } }); } }); }); listeners.authentication.socket.on ('listening', () => { var address = listeners.authentication.socket.address (); log.write ("Authentication listening on " + address.address + ":" + address.port); }); listeners.authentication.socket.bind (config.ports.radius_authentication); // RADIUS accounting listeners.accounting.socket.on ('message', (msg, rinfo) => { handlers.radius.accounting (msg, rinfo, (response, err) => { if (!err) { listeners.accounting.socket.send (response, 0, response.length, rinfo.port, rinfo.address, function (err, bytes) { if (err) { console.log ('Error sending response to ', rinfo); } }); } }); }); listeners.accounting.socket.on ('listening', () => { var address = listeners.accounting.socket.address (); log.write ("Accounting listening on " + address.address + ":" + address.port); }); listeners.accounting.socket.bind (config.ports.radius_accounting); // HTTP listener const respond = (res, content, status) => { var type = "text/plain"; if (typeof (content) != "string") { content = JSON.stringify (content); type = "application/json"; } res.writeHead (status, { "Content-Type": type, "Content-Length": content.length }).end (content); }; http.createServer (function (req, res) { var url = req.url.substring (0, req.url.lastIndexOf ("/")) || req.url; var endpoint = req.method + " " + url; switch (endpoint) { // Used for docker healthcheck case "GET /health": respond (res, "OK", 200); break; case "GET /users": handlers.user.getall ((users, err) => { if (err) { respond (res, err, 404); } else { respond (res, users, 200); } }); break; case "GET /user": handlers.user.getone (req.url.substring (req.url.lastIndexOf ("/") + 1), (user, err) => { if (err) { respond (res, err, 404); } else { respond (res, user, 200); } }); break; case "POST /user": var payload = ''; req.on ('data', chunk => { payload += chunk.toString (); }); req.on ('end', () => { handlers.user.create (payload, (status, err) => { if (err) { respond (res, err, 500); } else { respond (res, status, 200); } }); }); break; case "DELETE /user": handlers.user.delete (req.url.substring (req.url.lastIndexOf ("/") + 1), (status, err) => { if (err) { respond (res, err, 404); } else { respond (res, status, 200); } }); break; default: respond (res, "Not found", 404); } }).listen (config.ports.api); log.write ("API listening on port " + config.ports.api); // Exit handles const exitHandler = () => { log.write ('Shutting down'); listeners.authentication.socket.close (); listeners.accounting.socket.close (); log.write ('Exiting'); process.exit (); } process.on ('SIGTERM', exitHandler); process.on ('SIGINT', exitHandler); process.on ('SIGUSR1', exitHandler); process.on ('SIGUSR2', exitHandler);