syndicate-js/todo/driver-mdns/src/routes.js

120 lines
4.0 KiB
JavaScript
Raw Normal View History

2018-12-12 17:13:09 +00:00
//---------------------------------------------------------------------------
// @syndicate-lang/driver-mdns, mDNS support for Syndicate.
// Copyright (C) 2016-2018 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
const { Observe } = require("@syndicate-lang/core");
const { PeriodicTick } = activate require("@syndicate-lang/driver-timer");
const fs = require('fs');
assertion type Route(ifName, destIP, destMaskBits, gateway, flags) = Symbol.for('network-route');
assertion type DefaultGateway(ifName, gateway) = Symbol.for('network-default-gateway');
assertion type ScanRoutingTable() = Symbol.for('-@syndicate-lang/driver-mdns/scan-routing-table-');
export {
Route, DefaultGateway,
};
const flags = {
// From linux/route.h
UP: 0x0001, /* route usable */
GATEWAY: 0x0002, /* destination is a gateway */
HOST: 0x0004, /* host entry (net otherwise) */
REINSTATE: 0x0008, /* reinstate route after tmout */
DYNAMIC: 0x0010, /* created dyn. (by redirect) */
MODIFIED: 0x0020, /* modified dyn. (by redirect) */
MTU: 0x0040, /* specific MTU for this route */
WINDOW: 0x0080, /* per route window clamping */
IRTT: 0x0100, /* Initial round trip time */
REJECT: 0x0200, /* Reject route */
};
spawn named 'IPRouteDatabase' {
during Observe(Route(_, _, _, _, _)) assert ScanRoutingTable();
during Observe(DefaultGateway(_, _)) assert ScanRoutingTable();
during ScanRoutingTable() {
const refresh = () => {
const rows = fs.readFileSync('/proc/net/route').toString('utf-8')
.split('\n')
.filter((x) => x)
.map((x) => x.split('\t').map((f) => f.trim()));
const headings = rows.shift();
const data = rows.map((row) => {
const rec = {};
headings.forEach((heading, i) => { rec[heading] = row[i] || ''; });
return rec;
});
react {
2023-02-06 15:08:12 +00:00
stop on message PeriodicTick(5) refresh();
2018-12-12 17:13:09 +00:00
data.forEach((rec) => {
const destnet = littleEndianHex(rec.Destination);
const destmask = 32 - countZeroBits(littleEndianHex(rec.Mask));
const gateway = littleEndianHex(rec.Gateway);
assert Route(rec.Iface,
intToIPv4(destnet),
destmask,
intToIPv4(gateway),
decodeFlags(Number.parseInt(rec.Flags, 16)));
if (destnet === 0 && destmask === 0) {
assert DefaultGateway(rec.Iface, intToIPv4(gateway));
}
});
}
};
on start refresh();
}
}
function littleEndianHex(s) {
let byteCount = s.length / 2;
let v = Number.parseInt(s, 16);
let w = 0;
while (byteCount--) {
w *= 256;
w += (v & 255);
v >>= 8;
}
return w;
}
function decodeFlags(fs) {
let result = {};
for (let flagName in flags) {
if (fs & flags[flagName]) result[flagName] = true;
}
return result;
}
function intToIPv4(n) {
return '' + ((n >> 24) & 255)
+ '.' + ((n >> 16) & 255)
+ '.' + ((n >> 8) & 255)
+ '.' + (n & 255);
}
function countZeroBits(n) {
if (n === 0) return 32;
let i = 0;
while ((n & 1) === 0) {
i++;
n >>= 1;
}
return i;
}