Skip to content

Commit

Permalink
feat: add netstat utils (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahradelahi authored Apr 21, 2024
1 parent 323a9e6 commit d518fa9
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
strategy:
matrix:
node-version: [18, 20]
name: node ${{ matrix.node-version }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
Expand All @@ -55,4 +56,5 @@ jobs:
cache: 'pnpm'

- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm test
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@
"types": "./dist/ip/index.d.cts",
"default": "./dist/ip/index.cjs"
}
},
"./netstat": {
"import": {
"types": "./dist/netstat/index.d.ts",
"default": "./dist/netstat/index.js"
},
"require": {
"types": "./dist/netstat/index.d.cts",
"default": "./dist/netstat/index.cjs"
}
}
},
"author": "Shahrad Elahi <shahrad@litehex.com> (https://github.com/shahradelahi)",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * as ip from './ip';
export * as netstat from './netstat';
51 changes: 51 additions & 0 deletions src/netstat/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { execShell } from '@/utils/exec-shell';
import { removeDuplicate } from '@/utils/array';

// ------------------------

export interface ActiveConnection {
protocol: string;
program?: string;
recvQ: number;
sendQ: number;
address: string;
port: number;
state?: string;
}

export async function activeConnections(): Promise<ActiveConnection[]> {
const { error, data } = await execShell(['netstat', '-tuapn']);
if (error) {
throw error;
}

const lines = data.output.split('\n');
const ports: ActiveConnection[] = [];
for (const line of lines) {
const match =
/^(\w+)\s+(\d+)\s+(\d+)\s+((?:::)?(?:(?:(?:\d{1,3}\.){3}(?:\d{1,3}){1})?[0-9a-f]{0,4}:{0,2}){1,8}(?:::)?)\s+((?:::)?(?:(?:(?:\d{1,3}\.){3}(?:\d{1,3}){1})?[0-9a-f]{0,4}:{0,2}){1,8}(?:::)?\*?)\s+(\w+)?\s+(.*)$/.exec(
line
);
if (match) {
const port = match[4].split(':').at(-1);
const address = match[4].replace(`:${port}`, '');
const connection: ActiveConnection = {
protocol: match[1],
recvQ: Number(match[2]),
sendQ: Number(match[3]),
address: address,
port: Number(port),
state: match[6] ? match[6].trim() : undefined,
program: match[7].trim(),
};
ports.push(connection);
}
}

return ports;
}

export async function allocatedPorts(): Promise<number[]> {
const cns = await activeConnections();
return removeDuplicate(cns.map((cn) => cn.port));
}
9 changes: 9 additions & 0 deletions src/utils/array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function removeDuplicate<T>(d: T[]): T[] {
const final: T[] = [];
for (const item of d) {
if (!final.includes(item)) {
final.push(item);
}
}
return final;
}
21 changes: 21 additions & 0 deletions tests/netstat/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect } from 'chai';
import { IPV4_REGEX } from '@/ip';
import { activeConnections, allocatedPorts } from 'node-netkit/netstat';

describe('Active Connections', () => {
it('should get active connections', async () => {
const connections = await activeConnections();
expect(connections).to.be.an('array');
expect(connections.length).to.have.greaterThan(0);

expect(Object.keys(connections[0])).to.have.lengthOf(7);
expect(connections[0].address).to.match(IPV4_REGEX);
});

it('should get allocated ports', async () => {
for (const p of await allocatedPorts()) {
expect(p).to.be.greaterThan(0);
expect(p).to.be.lessThan(65535);
}
});
});
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"allowJs": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
"@/*": ["src/*"],
"node-netkit/*": ["dist/*"],
"node-netkit": ["dist/index.js"]
},
"outDir": "build"
},
Expand Down
2 changes: 1 addition & 1 deletion tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from 'tsup';
export default defineConfig({
clean: true,
dts: true,
entry: ['src/index.ts', 'src/ip/index.ts'],
entry: ['src/index.ts', 'src/ip/index.ts', 'src/netstat/index.ts'],
format: ['cjs', 'esm'],
target: 'esnext',
outDir: 'dist',
Expand Down

0 comments on commit d518fa9

Please sign in to comment.