]> PHS Git Server - phs-api.git/commitdiff
Adding disconnect, getStatus, and restart to the vpn.controller.js and associated...
authorcharleswrayjr <charleswrayjr@gmail.com>
Tue, 9 Sep 2025 16:40:55 +0000 (11:40 -0500)
committercharleswrayjr <charleswrayjr@gmail.com>
Tue, 9 Sep 2025 16:40:55 +0000 (11:40 -0500)
src/controllers/vpn.controller.js
src/routes/vpn.routes.js

index 16e39e1c9882d55f12b189d98cbc7ff6a2bb3545..2e64bce33135c44a0389b6bb44691b2df2296b2d 100644 (file)
@@ -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
index f4bf5db10b17d0e891daed5f771909a66b2cc4da..e34831c591992a0f847124301891f63609214cce 100644 (file)
@@ -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