Browse Source

feat(routes): parse device routes from ip route output

pull/2679/head
noderaven 2 weeks ago
parent
commit
94559c8fc6
  1. 32
      src/server/utils/routes.ts
  2. 38
      src/test/unit/routes.spec.ts

32
src/server/utils/routes.ts

@ -99,8 +99,40 @@ function collectDesiredRoutes(
return desired;
}
/**
* Parse `ip route show dev <inf>` output into routes tagged with whether wg-easy
* manages them. Kernel-installed routes (the connected subnet, link-local,
* multicast) are present but flagged unmanaged, so they are never removed and
* never re-added.
*/
function parseDeviceRoutes(output: string): DeviceRoute[] {
const result: DeviceRoute[] = [];
for (const line of output.trim().split('\n')) {
const trimmed = line.trim();
if (!trimmed) {
continue;
}
const dest = trimmed.split(/\s+/)[0];
if (!dest || dest === 'default') {
continue;
}
const normalized = normalizeRoute(dest);
if (!normalized) {
continue;
}
const managed =
!trimmed.includes('proto kernel') &&
isManageable(normalized.cidr, normalized.version);
result.push({ cidr: normalized.cidr, managed });
}
return result;
}
export const routesTestExports = {
normalizeRoute,
isManageable,
collectDesiredRoutes,
parseDeviceRoutes,
};

38
src/test/unit/routes.spec.ts

@ -2,8 +2,12 @@ import { describe, expect, test } from 'vitest';
import { routesTestExports } from '#server/utils/routes';
const { normalizeRoute, isManageable, collectDesiredRoutes } =
routesTestExports;
const {
normalizeRoute,
isManageable,
collectDesiredRoutes,
parseDeviceRoutes,
} = routesTestExports;
describe('routes', () => {
describe('normalizeRoute', () => {
@ -110,4 +114,34 @@ describe('routes', () => {
expect([...result[4]]).toEqual(['10.0.0.0/24']);
});
});
describe('parseDeviceRoutes', () => {
test('flags the kernel connected route as unmanaged', () => {
const output = [
'100.255.1.0/24 proto kernel scope link src 100.255.1.1',
'192.168.120.0/22 scope link',
].join('\n');
expect(parseDeviceRoutes(output)).toEqual([
{ cidr: '100.255.1.0/24', managed: false },
{ cidr: '192.168.120.0/22', managed: true },
]);
});
test('skips default routes', () => {
expect(parseDeviceRoutes('default via 10.0.0.1')).toEqual([]);
});
test('handles empty output', () => {
expect(parseDeviceRoutes('')).toEqual([]);
expect(parseDeviceRoutes('\n \n')).toEqual([]);
});
test('flags IPv6 link-local kernel route as unmanaged', () => {
const output = [
'fe80::/64 proto kernel metric 256 pref medium',
'2001:db8::/64 metric 1024 pref medium',
].join('\n');
expect(parseDeviceRoutes(output)).toEqual([
{ cidr: 'fe80::/64', managed: false },
{ cidr: '2001:db8::/64', managed: true },
]);
});
});
});

Loading…
Cancel
Save