// Baseline const product = 'NetRadius'; const version = '0.2.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 = {}; try { config = JSON.parse (fs.readFileSync ('./config.json').toString ()); } catch (error) { log.write ('Cannot open or read configuration file.'); log.write ('Using defaults'); config = { ports: { radius_authentication: 1812, radius_accounting: 1813, api: 8080 }, storage: "json:./data.json", client_secret: "password", default_vlan_enabled: false, mac_auth_only: false } } if (process.env['NETRADIUS_PORT_RADIUS_AUTH']) config.ports.radius_authentication = process.env['NETRADIUS_PORT_RADIUS_AUTH']; if (process.env['NETRADIUS_PORT_RADIUS_ACCT']) config.ports.radius_accounting = process.env['NETRADIUS_PORT_RADIUS_ACCT']; if (process.env['NETRADIUS_PORT_API']) config.ports.api = process.env['NETRADIUS_PORT_API']; if (process.env['NETRADIUS_STORAGE']) config.storage = process.env['NETRADIUS_STORAGE']; if (process.env['NETRADIUS_DEFAULT_VLAN']) config.default_vlan_enabled = process.env['NETRADIUS_DEFAULT_VLAN']; if (process.env['NETRADIUS_DEFAULT_VLAN_ID']) config.default_vlan_id = process.env['NETRADIUS_DEFAULT_VLAN_ID']; if (process.env['NETRADIUS_CLIENT_SECRET']) config.client_secret = process.env['NETRADIUS_CLIENT_SECRET']; if (process.env['NETRADIUS_MAC_AUTH_ONLY']) config.mac_auth_only = process.env['NETRADIUS_MAC_AUTH_ONLY']; // Set defaults if (!config.ports.radius_authentication) config.ports.radius_authentication = 1812; if (!config.ports.radius_accounting) config.ports.radius_accounting = 1813; if (!config.ports.api) config.ports.api = 8080; // 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 (8080); 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);