From: charleswrayjr Date: Tue, 9 Sep 2025 16:40:55 +0000 (-0500) Subject: Adding disconnect, getStatus, and restart to the vpn.controller.js and associated... X-Git-Url: https://git.phasecustomsoft.com/static/git-logo.png?a=commitdiff_plain;h=8907c6a70bb827f60736f9f6c2c62462229b4249;p=phs-api.git Adding disconnect, getStatus, and restart to the vpn.controller.js and associated routes in vpn.routes.js. --- diff --git a/src/controllers/vpn.controller.js b/src/controllers/vpn.controller.js index 16e39e1..2e64bce 100644 --- a/src/controllers/vpn.controller.js +++ b/src/controllers/vpn.controller.js @@ -1,5 +1,9 @@ const { Client } = require( 'ssh2' ); const fs = require( 'fs' ); +const net = require( 'net' ); +const util = require( 'util' ); +const exec = require( 'child_process' ).execSync; +const execPromise = util.promisify(exec); /** * @@ -143,7 +147,7 @@ module.exports = { next( error ); } ).connect( sshConfig ); }, - getAvailableClients:async ( req, res, next ) => { + getAvailableClients: async ( req, res, next ) => { const conn = new Client(); conn.on( 'ready', () => { const commands = [ @@ -207,7 +211,7 @@ module.exports = { next( error ); } ).connect( sshConfig ); }, - getClients:async ( req, res, next ) => { + getClients: async ( req, res, next ) => { const conn = new Client(); conn.on( 'ready', () => { const command = `cat /var/log/openvpn/openvpn-status.log`; @@ -235,5 +239,97 @@ module.exports = { const error = new createError( 500, `SSH connection failed: ${ err.message }` ); next( error ); } ).connect( sshConfig ); + }, + disconnect: async ( req, res, next ) => { + const { clientName, duration } = req.body; // duration in minutes + if (!clientName) { + return next(new createError(400, 'Client name required')); + } + + try { + // Read from the OpenVPN status log to get the client's real IP + const statusContent = fs.readFileSync('/var/log/openvpn/openvpn-status.log', 'utf8'); + let clientIp = null; + const clientLine = statusContent.split('\n').find(line => + line.startsWith(`${clientName},`) && !line.startsWith('Virtual Address') + ); + if (clientLine) { + const [, realAddress] = clientLine.split(','); + clientIp = realAddress.split(':')[0]; + } else { + return next(new createError(404, `Client ${clientName} not connected`)); + } + + // Disconnect client via management interface + const client = new net.Socket(); + client.connect(7505, 'localhost', () => { + logger.info('Connected to OpenVPN management interface'); + client.write(`client-kill ${clientName}\n`); + }); + + client.on('data', async (data) => { + const response = data.toString(); + if (response.includes('SUCCESS: client-kill command succeeded')) { + if (duration && clientIp) { + // Add iptables rule to block client IP for duration + const conn = new Client(); + conn.on('ready', () => { + const commands = [ + `sudo iptables -A INPUT -s ${clientIp} -p tcp --dport 1194 -j DROP`, + `sleep ${duration * 60} && sudo iptables -D INPUT -s ${clientIp} -p tcp --dport 1194 -j DROP &`, + ]; + conn.exec(commands.join(' && '), (err, stream) => { + if (err) { + conn.end(); + client.destroy(); + return next(new createError(500, `IPTables command failed: ${err.message}`)); + } + stream.on('close', (code) => { + conn.end(); + client.destroy(); + if (code === 0) { + res.json({ message: `Client ${clientName} disconnected for ${duration} minutes` }); + } else { + next(new createError(500, `IPTables command failed`)); + } + }); + }); + }).on('error', (err) => { + client.destroy(); + next(new createError(500, `SSH connection failed: ${err.message}`)); + }).connect(sshConfig); + } else { + client.destroy(); + res.json({ message: `Client ${clientName} disconnected` }); + } + } else { + client.destroy(); + next(new createError(500, `Failed to disconnect client: ${response}`)); + } + }); + + client.on('error', (err) => { + client.destroy(); + next(new createError(500, `Management interface connection failed: ${err.message}`)); + }); + } catch (error) { + next(new createError(500, `Failed to process disconnection: ${error.message}`)); + } + }, + getStatus: async ( req, res, next ) => { + try { + const { stdout } = await execPromise('systemctl is-active openvpn@server'); + res.json({ status: stdout.trim() }); + } catch (error) { + return next(new createError(500, `Failed to check VPN status: ${error.message}`)); + } + }, + restart: async ( req, res, next ) => { + try { + await execPromise('systemctl restart openvpn@server'); + res.json({ message: 'VPN restarted successfully' }); + } catch (error) { + return next(new createError(500, `Failed to restart VPN: ${error.message}`)); + } } }; \ No newline at end of file diff --git a/src/routes/vpn.routes.js b/src/routes/vpn.routes.js index f4bf5db..e34831c 100644 --- a/src/routes/vpn.routes.js +++ b/src/routes/vpn.routes.js @@ -9,6 +9,9 @@ module.exports = ( passport ) => { router.put( '/revoke-client/', vpnController.revokeClient ); router.get( '/clients', vpnController.getClients ); router.get( '/available-clients', vpnController.getAvailableClients ); + router.get( '/status', vpnController.getStatus ); + router.put( '/disconnect', vpnController.disconnect ); + router.put( '/restart', vpnController.restart ); return router; }; \ No newline at end of file