выпилил obsolete скрипты
This commit is contained in:
parent
a0a7794cb0
commit
3c59c10a7c
15
README.md
15
README.md
|
|
@ -1,18 +1,5 @@
|
||||||
# Protected Resources
|
# Protected Resources
|
||||||
Список ресурсов для настройки родительского контроля чтобы заблокировать доступ детям до запрещённых в РФ вражеских сервисов.
|
Список ресурсов для настройки родительского контроля чтобы заблокировать доступ детям до запрещённых в РФ вражеских сервисов.
|
||||||
|
|
||||||
## networks
|
## resources
|
||||||
Каталог с файлами сервисов и их подсетей
|
Каталог с файлами сервисов и их подсетей
|
||||||
|
|
||||||
### Установка
|
|
||||||
```shell
|
|
||||||
apk add php php-session php-curl jq git
|
|
||||||
cd /opt
|
|
||||||
git clone https://git.kirillius.ru/kirillius/protected-resources-list.git
|
|
||||||
cd /opt/protected-resources-list/
|
|
||||||
chmod -R +x ./bin
|
|
||||||
ln -s /opt/protected-resources-list/bin/webui /etc/init.d/webui
|
|
||||||
cp config.json.example config.json
|
|
||||||
rc-update add webui
|
|
||||||
/etc/init.d/webui start
|
|
||||||
```
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import {JSONRPC} from "./jrpc.js";
|
|
||||||
|
|
||||||
const App = {
|
|
||||||
config: {},
|
|
||||||
networks: {},
|
|
||||||
RPC: JSONRPC
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
App.auth = async function () {
|
|
||||||
let authorized = await JSONRPC.__invoke("auth");
|
|
||||||
if (!authorized) {
|
|
||||||
do {
|
|
||||||
let pass = prompt("Password");
|
|
||||||
authorized = await JSONRPC.__invoke("auth", {
|
|
||||||
"password": pass
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!authorized) {
|
|
||||||
alert("Wrong password");
|
|
||||||
}
|
|
||||||
} while (!authorized);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.config = await JSONRPC.__invoke("getConfig");
|
|
||||||
this.networks = await JSONRPC.__invoke("getNetworks");
|
|
||||||
|
|
||||||
|
|
||||||
for (const key of this.config.plugins) {
|
|
||||||
$("body").append("<" + "script type='module' src='/plugins/" + key + "/plugin.js'><" + "/script>");
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#loading").hide();
|
|
||||||
|
|
||||||
this.fillNetworks();
|
|
||||||
|
|
||||||
$("#panel").show();
|
|
||||||
|
|
||||||
let invalidNetworks = await JSONRPC.__invoke("getInvalidNetworks");
|
|
||||||
|
|
||||||
if (invalidNetworks.length > 0) {
|
|
||||||
$("body").append(`<span>There are invalid networks <BR>` + invalidNetworks.join("<BR>") + ` <BR></span>`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.fillNetworks = function () {
|
|
||||||
const that = this;
|
|
||||||
let proto = $("#net-table tr");
|
|
||||||
proto.detach();
|
|
||||||
|
|
||||||
for (const net in this.networks) {
|
|
||||||
let item = proto.clone();
|
|
||||||
item.find("input").prop('checked', this.config.networks.indexOf(net) !== -1).change(function () {
|
|
||||||
if ($(this).prop('checked')) {
|
|
||||||
that.config.networks.push(net);
|
|
||||||
} else {
|
|
||||||
that.config.networks = that.config.networks.filter(e => e !== net);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
item.find("span").text(net);
|
|
||||||
$("#net-table").append(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.render = async function () {
|
|
||||||
await this.auth();
|
|
||||||
$("#save").click(function () {
|
|
||||||
const self = $(this);
|
|
||||||
self.prop("disabled", true);
|
|
||||||
(async function () {
|
|
||||||
await JSONRPC.__invoke("setConfig", App.config);
|
|
||||||
alert("Config saved!");
|
|
||||||
self.prop("disabled", false);
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export {App};
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Routing config</title>
|
|
||||||
<script src="jquery-3.7.1.min.js" type="text/javascript"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<span id="loading">Loading...</span>
|
|
||||||
|
|
||||||
<div style="display: none" id="panel">
|
|
||||||
Selected networks:
|
|
||||||
<table id="net-table">
|
|
||||||
<tr>
|
|
||||||
<td><input type="checkbox"></td>
|
|
||||||
<td><span>Network name</span></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div id="buttons">
|
|
||||||
<button id="save">Save</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module">
|
|
||||||
import {App} from "./App.js";
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
App.render();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,59 +0,0 @@
|
||||||
export const JSONRPC = {
|
|
||||||
url: "/rpc",
|
|
||||||
__id: 1,
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param method
|
|
||||||
* @param params
|
|
||||||
* @returns Object
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
__invoke: async function (method, params) {
|
|
||||||
if(params === undefined){
|
|
||||||
params = {};
|
|
||||||
}
|
|
||||||
const request = await JSONRPC.__performRequest(method, params);
|
|
||||||
|
|
||||||
if (!request.success) {
|
|
||||||
console.error(request.result);
|
|
||||||
throw new Error("Failed to invoke method " + method + " with params " + JSON.stringify(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
return request.result;
|
|
||||||
},
|
|
||||||
__performRequest: async function (method, params) {
|
|
||||||
const __this = this;
|
|
||||||
const resp = await fetch(
|
|
||||||
__this.url,
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
mode: "cors",
|
|
||||||
cache: "no-cache",
|
|
||||||
credentials: "include",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
redirect: "follow",
|
|
||||||
referrerPolicy: "no-referrer",
|
|
||||||
body: JSON.stringify({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
method: method,
|
|
||||||
params: params,
|
|
||||||
id: __this.__id++
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const success = resp.status === 200;
|
|
||||||
const result = (success ? (await resp.json()).result : {
|
|
||||||
"error": true,
|
|
||||||
"code": resp.status,
|
|
||||||
"status": resp.statusText,
|
|
||||||
"body": await resp.text()
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
"result": result,
|
|
||||||
"success": success
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
require_once dirname(__DIR__) . "/loader.php";
|
|
||||||
require_once dirname(__DIR__) . "/plugins/openvpn/Openvpn.php";
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (!isset($argv[1])) {
|
|
||||||
throw new RuntimeException("Output config is not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
$rpc = new StaticRPC();
|
|
||||||
$instance = $rpc->getPlugins()["openvpn"] ?? null;
|
|
||||||
if ($instance === null) {
|
|
||||||
throw new RuntimeException("Plugin is not enabled");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @var Custom $instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
$config = $instance->getRoutingConfig();
|
|
||||||
$outfile = $argv[1];
|
|
||||||
file_put_contents($outfile, implode("\n", $config));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "\nError:" . $e->getMessage() . "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
require_once dirname(__DIR__) . "/loader.php";
|
|
||||||
require_once dirname(__DIR__) . "/plugins/netsync/Netsync.php";
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
|
|
||||||
$rpc = new StaticRPC();
|
|
||||||
$instance = $rpc->getPlugins()["netsync"] ?? null;
|
|
||||||
if ($instance === null) {
|
|
||||||
throw new RuntimeException("Plugin is not enabled");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @var Netsync $instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
$config = $instance->sync();
|
|
||||||
|
|
||||||
var_dump($config);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "\nError:" . $e->getMessage() . "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
#!/sbin/openrc-run
|
|
||||||
command="/opt/protected-resources-list/bin/webui-server"
|
|
||||||
command_background=true
|
|
||||||
pidfile="/run/${RC_SVCNAME}.pid"
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
SELFDIR=`dirname $0`
|
|
||||||
ROOT=`realpath $SELFDIR/..`
|
|
||||||
CFGFILE=$ROOT/config.json
|
|
||||||
|
|
||||||
if ! test -f "$CFGFILE"; then
|
|
||||||
echo Config file $CFGFILE not found
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
HOST=`jq -r .web.host $CFGFILE`
|
|
||||||
PORT=`jq -r .web.port $CFGFILE`
|
|
||||||
#TODO FIXME !!!!
|
|
||||||
killall php
|
|
||||||
cd $ROOT
|
|
||||||
php $ROOT/loader.php --init
|
|
||||||
php -S $HOST:$PORT $ROOT/server.php
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Config implements ArrayAccess
|
|
||||||
{
|
|
||||||
private string $path;
|
|
||||||
|
|
||||||
public function asArray(): array
|
|
||||||
{
|
|
||||||
return $this->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fromArray($a)
|
|
||||||
{
|
|
||||||
$this->data = $a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->path = dirname(__DIR__) . "/config.json";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read(): void
|
|
||||||
{
|
|
||||||
$this->data = @json_decode(@file_get_contents($this->path), true);
|
|
||||||
if ($this->data == null) {
|
|
||||||
throw new RuntimeException("Failed to read or parse config file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(): void
|
|
||||||
{
|
|
||||||
file_put_contents($this->path, json_encode($this->data,JSON_PRETTY_PRINT));
|
|
||||||
}
|
|
||||||
|
|
||||||
private mixed $data = [];
|
|
||||||
|
|
||||||
|
|
||||||
public function offsetExists(mixed $offset): bool
|
|
||||||
{
|
|
||||||
return isset($this->data[$offset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetGet(mixed $offset): mixed
|
|
||||||
{
|
|
||||||
return $this->data[$offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetSet(mixed $offset, mixed $value): void
|
|
||||||
{
|
|
||||||
$this->data[$offset] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetUnset(mixed $offset): void
|
|
||||||
{
|
|
||||||
unset($this->data[$offset]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
interface IPluggable
|
|
||||||
{
|
|
||||||
public function onServerStarted();
|
|
||||||
public function onInit(PluginContext $context);
|
|
||||||
public function onSync(array $remote_config);
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class IPv4Subnet
|
|
||||||
{
|
|
||||||
|
|
||||||
private string $address;
|
|
||||||
private int $prefix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $subnetAddress
|
|
||||||
* @param int $prefix
|
|
||||||
*/
|
|
||||||
public function __construct(string $subnetAddress, int $prefix)
|
|
||||||
{
|
|
||||||
$this->address = $subnetAddress;
|
|
||||||
if (ip2long($subnetAddress) === false) {
|
|
||||||
throw new RuntimeException("Invalid subnet address: " . $subnetAddress);
|
|
||||||
}
|
|
||||||
$this->prefix = $prefix;
|
|
||||||
if ($prefix < 0 or $prefix > 32) {
|
|
||||||
throw new RuntimeException("Invalid subnet prefix: " . $prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFirstAddress()
|
|
||||||
{
|
|
||||||
$a = ip2long($this->address);
|
|
||||||
$mask = ip2long($this->getNetMask());
|
|
||||||
return long2ip($a & $mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastAddress()
|
|
||||||
{
|
|
||||||
return long2ip(ip2long($this->getFirstAddress()) + $this->getAddressCount() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAddressCount()
|
|
||||||
{
|
|
||||||
return pow(2, 32 - $this->prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNetMask()
|
|
||||||
{
|
|
||||||
return long2ip(-1 << (32 - $this->prefix));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkConfigReader
|
|
||||||
{
|
|
||||||
private array $configs = [];
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$path = dirname(__DIR__) . "/networks";
|
|
||||||
foreach (new IteratorIterator(new DirectoryIterator($path)) as $file) {
|
|
||||||
/**
|
|
||||||
* @var SplFileInfo $file
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ($file->getExtension() === "json") {
|
|
||||||
$key = $file->getBasename(".json");
|
|
||||||
$value = @json_decode(@file_get_contents($file->getPathname()), true);
|
|
||||||
|
|
||||||
if ($value === null) {
|
|
||||||
throw new RuntimeException("Network file " . $file->getBasename() . " is invalid or cannot be read");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->configs[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConfigs(): array
|
|
||||||
{
|
|
||||||
return $this->configs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
abstract class Plugin implements IPluggable
|
|
||||||
{
|
|
||||||
protected PluginContext $context;
|
|
||||||
protected array $config;
|
|
||||||
|
|
||||||
public function onServerStarted()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSync($remote_config)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onInit(PluginContext $context): void
|
|
||||||
{
|
|
||||||
$this->context = $context;
|
|
||||||
$this->checkConfig();
|
|
||||||
$this->config = $this->context->getConfig()[$context->getName()];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function checkConfig(): void
|
|
||||||
{
|
|
||||||
$config = $this->context->getConfig();
|
|
||||||
$defaults = $this->context->getMetadata()["config"];
|
|
||||||
$name = $this->context->getName();
|
|
||||||
|
|
||||||
if (!isset($config[$name])) {
|
|
||||||
$config[$name] = $defaults;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($defaults as $key => $value) {
|
|
||||||
if (!isset($config[$name][$key])) {
|
|
||||||
$config[$name][$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function saveConfig()
|
|
||||||
{
|
|
||||||
$wrapper = $this->context->getConfig();
|
|
||||||
$wrapper[$this->context->getName()] = $this->config;
|
|
||||||
$wrapper->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class PluginContext
|
|
||||||
{
|
|
||||||
private RPC $RPC;
|
|
||||||
private Config $config;
|
|
||||||
private array $metadata;
|
|
||||||
private string $name;
|
|
||||||
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param RPC $RPC
|
|
||||||
* @param Config $config
|
|
||||||
* @param array $metadata
|
|
||||||
* @param string $name
|
|
||||||
*/
|
|
||||||
public function __construct(RPC $RPC, Config $config, array $metadata, string $name)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->RPC = $RPC;
|
|
||||||
$this->config = $config;
|
|
||||||
$this->metadata = $metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRPC(): RPC
|
|
||||||
{
|
|
||||||
return $this->RPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConfig(): Config
|
|
||||||
{
|
|
||||||
return $this->config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMetadata(): array
|
|
||||||
{
|
|
||||||
return $this->metadata;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
167
classes/RPC.php
167
classes/RPC.php
|
|
@ -1,167 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class RPC
|
|
||||||
{
|
|
||||||
protected Config $config;
|
|
||||||
protected array $plugins = [];
|
|
||||||
|
|
||||||
public function getPlugins(): array
|
|
||||||
{
|
|
||||||
return $this->plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->config = new Config();
|
|
||||||
$this->config->read();
|
|
||||||
|
|
||||||
foreach ($this->config["plugins"] as $plugin) {
|
|
||||||
try {
|
|
||||||
$meta = $this->getPluginMetadata($plugin);
|
|
||||||
$inst = $this->loadPlugin($plugin, $meta["class"]);
|
|
||||||
$inst->onInit(new PluginContext($this, $this->config, $meta, $plugin));
|
|
||||||
} catch (Error $e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getPluginMetadata($name): array
|
|
||||||
{
|
|
||||||
$root = dirname(__DIR__) . "/plugins/" . $name;
|
|
||||||
if (!file_exists($root)) {
|
|
||||||
throw new RuntimeException("Plugin $name dir not found");
|
|
||||||
}
|
|
||||||
$metafile = $root . "/metadata.json";
|
|
||||||
if (!file_exists($metafile)) {
|
|
||||||
throw new RuntimeException("Plugin $name metadata not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
$meta = @json_decode(@file_get_contents($metafile), true);
|
|
||||||
|
|
||||||
if ($meta === null) {
|
|
||||||
throw new RuntimeException("Unable to parse $name plugin metadata");
|
|
||||||
}
|
|
||||||
return $meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadPlugin($name, $classname): IPluggable
|
|
||||||
{
|
|
||||||
$file = dirname(__DIR__) . "/plugins/" . $name . "/" . $classname . ".php";
|
|
||||||
if (!file_exists($file)) {
|
|
||||||
throw new RuntimeException("Plugin $name class $classname not found");
|
|
||||||
}
|
|
||||||
require_once $file;
|
|
||||||
|
|
||||||
$instance = new $classname();
|
|
||||||
if (!($instance instanceof IPluggable)) {
|
|
||||||
throw new RuntimeException("Class $classname have to implement IPluggable");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->plugins[$name] = $instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConfig(): array
|
|
||||||
{
|
|
||||||
$this->checkAuth();
|
|
||||||
return $this->config->asArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setConfig($config): bool
|
|
||||||
{
|
|
||||||
$this->config->fromArray($config);
|
|
||||||
$this->config->save();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkAuth(): void
|
|
||||||
{
|
|
||||||
$auth = $_SESSION["auth"] ?? false;
|
|
||||||
if (!$auth) {
|
|
||||||
throw new RuntimeException("Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNetworks(): array
|
|
||||||
{
|
|
||||||
$this->checkAuth();
|
|
||||||
return (new NetworkConfigReader())->getConfigs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getInvalidNetworks(): array
|
|
||||||
{
|
|
||||||
$this->checkAuth();
|
|
||||||
$invalid = [];
|
|
||||||
foreach ((new NetworkConfigReader())->getConfigs() as $config) {
|
|
||||||
foreach ($config["networks"] as $network) {
|
|
||||||
if (!RouteUtil::validateSubnet($network)) {
|
|
||||||
$invalid[] = $network;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function logout(): void
|
|
||||||
{
|
|
||||||
$_SESSION["auth"] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function auth($params): bool
|
|
||||||
{
|
|
||||||
if (isset($params["password"])) {
|
|
||||||
if ($this->comparePassword($params["password"])) {
|
|
||||||
return $_SESSION["auth"] = true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $_SESSION["auth"] ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function comparePassword($passwd): bool
|
|
||||||
{
|
|
||||||
$pass = $this->config["password"];
|
|
||||||
if ($pass["type"] == "plaintext") {
|
|
||||||
return $pass["data"] == $passwd;
|
|
||||||
} else if ($pass["type"] == "hash") {
|
|
||||||
return $this->hash($passwd) == $pass["data"];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function hash($what): string
|
|
||||||
{
|
|
||||||
return md5(sha1($what) . md5($what));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isInternalMethod($name)
|
|
||||||
{
|
|
||||||
$cls = new ReflectionClass(IPluggable::class);
|
|
||||||
return $cls->hasMethod($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke($method, $args)
|
|
||||||
{
|
|
||||||
$parts = explode("::", $method);
|
|
||||||
$isPlugin = count($parts) > 1;
|
|
||||||
|
|
||||||
if ($isPlugin) {
|
|
||||||
$this->checkAuth();
|
|
||||||
$plugin = $this->plugins[$parts[0]];
|
|
||||||
$methodname = $parts[1];
|
|
||||||
if ($this->isInternalMethod($methodname)) {
|
|
||||||
throw new RuntimeException("Unable to invoke internal methods");
|
|
||||||
}
|
|
||||||
return call_user_func([$plugin, $methodname], $args);
|
|
||||||
} else {
|
|
||||||
$cls = new ReflectionClass(__CLASS__);
|
|
||||||
$method = $cls->getMethod($method);
|
|
||||||
if (!$method or !$method->isPublic()) {
|
|
||||||
throw new RuntimeException("Unable to find method");
|
|
||||||
}
|
|
||||||
return $method->invoke($this, $args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class RouteUtil
|
|
||||||
{
|
|
||||||
public static function validateSubnet($subnet)
|
|
||||||
{
|
|
||||||
$parts = explode("/", $subnet);
|
|
||||||
if (count($parts) != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$ipv4subnet = new IPv4Subnet($parts[0], $parts[1]);
|
|
||||||
return $parts[0] == $ipv4subnet->getFirstAddress();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
class RoutingTableReader
|
|
||||||
{
|
|
||||||
private $routes = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getRoutes(): array
|
|
||||||
{
|
|
||||||
return $this->routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$result = @shell_exec("ip --json route show");
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
throw new RuntimeException("Failed to read routing table");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$this->routes = @json_decode($result, true);
|
|
||||||
|
|
||||||
if ($this->routes === null) {
|
|
||||||
throw new RuntimeException("Failed to parse json output");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->routes as $key => &$route) {
|
|
||||||
if ($route["dst"] === "default") {
|
|
||||||
$route["dst"] = "0.0.0.0/0";
|
|
||||||
} elseif (!str_contains($route["dst"], "/")) {
|
|
||||||
$route["dst"] .= "/32";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class StaticRPC extends RPC
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPlugins(): array
|
|
||||||
{
|
|
||||||
return $this->plugins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class WebRouter
|
|
||||||
{
|
|
||||||
private string $requestBody;
|
|
||||||
private string $requestedFile;
|
|
||||||
private string $URI;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->requestBody = @file_get_contents('php://input');
|
|
||||||
$this->requestedFile = dirname(__DIR__) . "/" . $_SERVER["REQUEST_URI"];
|
|
||||||
$this->URI = $_SERVER["REQUEST_URI"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleRequest(): void
|
|
||||||
{
|
|
||||||
@session_start();
|
|
||||||
try {
|
|
||||||
if (str_starts_with($this->URI, "/assets") or str_starts_with($this->URI, "/plugins") and str_ends_with($this->URI, ".js")) {
|
|
||||||
$this->handleAsset();
|
|
||||||
} elseif (!str_starts_with($this->URI, "/rpc")) {
|
|
||||||
$this->redirect("/assets/index.html");
|
|
||||||
} else {
|
|
||||||
$this->handleJRPC();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
session_write_close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleJRPC(): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$request = @json_decode($this->requestBody, true);
|
|
||||||
if ($request === null) {
|
|
||||||
throw new RuntimeException("Failed to parse JRPC");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (["id", "jsonrpc", "method", "params"] as $param) {
|
|
||||||
if (!isset($request[$param])) {
|
|
||||||
throw new RuntimeException("Bad JRPC structure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$rpc = new RPC();
|
|
||||||
$response = $rpc($request["method"], $request["params"]);
|
|
||||||
|
|
||||||
header("content-type: application/json");
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
"jsonrpc" => "2.0",
|
|
||||||
"id" => $request["id"] ?? 0,
|
|
||||||
"result" => $response
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
http_response_code(500);
|
|
||||||
echo json_encode([
|
|
||||||
"jsonrpc" => "2.0",
|
|
||||||
"id" => $request["id"],
|
|
||||||
"error" => $e->getMessage()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleAsset(): void
|
|
||||||
{
|
|
||||||
if (!file_exists($this->requestedFile)) {
|
|
||||||
http_response_code(404);
|
|
||||||
echo "File not found: " . $this->URI;
|
|
||||||
} else {
|
|
||||||
header("content-type: " . mime_content_type($this->requestedFile));
|
|
||||||
echo file_get_contents($this->requestedFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private function redirect($where): void
|
|
||||||
{
|
|
||||||
http_response_code(302);
|
|
||||||
header("location: " . $where);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
<?php
|
|
||||||
if (!function_exists('mime_content_type')) {
|
|
||||||
|
|
||||||
function mime_content_type($filename): bool|string
|
|
||||||
{
|
|
||||||
$mime_types = array(
|
|
||||||
'txt' => 'text/plain',
|
|
||||||
'htm' => 'text/html',
|
|
||||||
'html' => 'text/html',
|
|
||||||
'php' => 'text/html',
|
|
||||||
'css' => 'text/css',
|
|
||||||
'js' => 'application/javascript',
|
|
||||||
'json' => 'application/json',
|
|
||||||
'xml' => 'application/xml',
|
|
||||||
'swf' => 'application/x-shockwave-flash',
|
|
||||||
'flv' => 'video/x-flv',
|
|
||||||
|
|
||||||
// images
|
|
||||||
'png' => 'image/png',
|
|
||||||
'jpe' => 'image/jpeg',
|
|
||||||
'jpeg' => 'image/jpeg',
|
|
||||||
'jpg' => 'image/jpeg',
|
|
||||||
'gif' => 'image/gif',
|
|
||||||
'bmp' => 'image/bmp',
|
|
||||||
'ico' => 'image/vnd.microsoft.icon',
|
|
||||||
'tiff' => 'image/tiff',
|
|
||||||
'tif' => 'image/tiff',
|
|
||||||
'svg' => 'image/svg+xml',
|
|
||||||
'svgz' => 'image/svg+xml',
|
|
||||||
|
|
||||||
// archives
|
|
||||||
'zip' => 'application/zip',
|
|
||||||
'rar' => 'application/x-rar-compressed',
|
|
||||||
'exe' => 'application/x-msdownload',
|
|
||||||
'msi' => 'application/x-msdownload',
|
|
||||||
'cab' => 'application/vnd.ms-cab-compressed',
|
|
||||||
|
|
||||||
// audio/video
|
|
||||||
'mp3' => 'audio/mpeg',
|
|
||||||
'qt' => 'video/quicktime',
|
|
||||||
'mov' => 'video/quicktime',
|
|
||||||
|
|
||||||
// adobe
|
|
||||||
'pdf' => 'application/pdf',
|
|
||||||
'psd' => 'image/vnd.adobe.photoshop',
|
|
||||||
'ai' => 'application/postscript',
|
|
||||||
'eps' => 'application/postscript',
|
|
||||||
'ps' => 'application/postscript',
|
|
||||||
|
|
||||||
// ms office
|
|
||||||
'doc' => 'application/msword',
|
|
||||||
'rtf' => 'application/rtf',
|
|
||||||
'xls' => 'application/vnd.ms-excel',
|
|
||||||
'ppt' => 'application/vnd.ms-powerpoint',
|
|
||||||
|
|
||||||
// open office
|
|
||||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
|
||||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
|
||||||
);
|
|
||||||
|
|
||||||
$parts = explode('.', $filename);
|
|
||||||
$ext = strtolower(array_pop($parts));
|
|
||||||
if (array_key_exists($ext, $mime_types)) {
|
|
||||||
return $mime_types[$ext];
|
|
||||||
} elseif (function_exists('finfo_open')) {
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME);
|
|
||||||
$mimetype = finfo_file($finfo, $filename);
|
|
||||||
finfo_close($finfo);
|
|
||||||
return $mimetype;
|
|
||||||
} else {
|
|
||||||
return 'application/octet-stream';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"password": {
|
|
||||||
"type": "plaintext",
|
|
||||||
"data": "admin"
|
|
||||||
},
|
|
||||||
"networks": [
|
|
||||||
"google"
|
|
||||||
],
|
|
||||||
"web": {
|
|
||||||
"port":8000,
|
|
||||||
"host":"0.0.0.0"
|
|
||||||
},
|
|
||||||
"plugins":["updates"]
|
|
||||||
}
|
|
||||||
15
loader.php
15
loader.php
|
|
@ -1,15 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
require_once __DIR__ . "/common.inc.php";
|
|
||||||
spl_autoload_register(function ($classname) {
|
|
||||||
require_once __DIR__ . "/classes/" . $classname . ".php";
|
|
||||||
});
|
|
||||||
if (isset($argv) and in_array("--init", $argv)) {
|
|
||||||
$rpc = new StaticRPC();
|
|
||||||
foreach ($rpc->getPlugins() as $plugin => $instance) {
|
|
||||||
/**
|
|
||||||
* @var IPluggable $instance
|
|
||||||
*/
|
|
||||||
$instance->onServerStarted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"description": "facebook, instagram, oculus",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"213.102.128.0/24",
|
|
||||||
"204.15.20.0/22",
|
|
||||||
"199.201.0.0/16",
|
|
||||||
"185.89.0.0/16",
|
|
||||||
"185.60.216.0/21",
|
|
||||||
"179.60.0.0/16",
|
|
||||||
"173.252.0.0/16",
|
|
||||||
"173.194.10.0/24",
|
|
||||||
"164.163.191.64/26",
|
|
||||||
"163.70.0.0/16",
|
|
||||||
"157.240.0.0/16",
|
|
||||||
"147.75.0.0/16",
|
|
||||||
"142.250.0.0/15",
|
|
||||||
"129.134.0.0/16",
|
|
||||||
"103.4.0.0/16",
|
|
||||||
"102.221.0.0/16",
|
|
||||||
"102.132.0.0/16",
|
|
||||||
"99.84.0.0/16",
|
|
||||||
"87.245.208.0/24",
|
|
||||||
"77.240.43.0/24",
|
|
||||||
"74.119.0.0/16",
|
|
||||||
"69.171.0.0/16",
|
|
||||||
"69.63.0.0/16",
|
|
||||||
"66.220.0.0/16",
|
|
||||||
"57.141.0.0/16",
|
|
||||||
"57.144.222.0/24",
|
|
||||||
"45.64.0.0/16",
|
|
||||||
"45.130.4.0/24",
|
|
||||||
"31.13.0.0/16"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"description": "broadcom.com",
|
|
||||||
"domains": ["broadcom.com","omnissa.com"],
|
|
||||||
"networks": [
|
|
||||||
"172.66.0.165/32",
|
|
||||||
"162.159.140.167/32",
|
|
||||||
"54.68.22.26/32",
|
|
||||||
"50.112.202.115/32",
|
|
||||||
"52.13.171.212/32",
|
|
||||||
"2.19.183.16/32",
|
|
||||||
"2.19.183.47/32",
|
|
||||||
"129.153.117.201/32",
|
|
||||||
"23.73.4.0/24",
|
|
||||||
"184.50.200.7/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"description": "cloudflare",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"173.245.48.0/20",
|
|
||||||
"103.21.244.0/22",
|
|
||||||
"103.22.200.0/22",
|
|
||||||
"103.31.4.0/22",
|
|
||||||
"141.101.64.0/18",
|
|
||||||
"108.162.192.0/18",
|
|
||||||
"190.93.240.0/20",
|
|
||||||
"188.114.96.0/20",
|
|
||||||
"197.234.240.0/22",
|
|
||||||
"198.41.128.0/17",
|
|
||||||
"162.158.0.0/15",
|
|
||||||
"104.16.0.0/13",
|
|
||||||
"104.24.0.0/14",
|
|
||||||
"172.64.0.0/13",
|
|
||||||
"131.0.72.0/22"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
"description": "amazon cloudfront",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"108.138.0.0/15",
|
|
||||||
"108.156.0.0/14",
|
|
||||||
"111.13.0.0/16",
|
|
||||||
"116.129.226.0/24",
|
|
||||||
"118.193.97.0/24",
|
|
||||||
"119.147.182.0/24",
|
|
||||||
"120.232.0.0/16",
|
|
||||||
"120.52.0.0/16",
|
|
||||||
"13.0.0.0/8",
|
|
||||||
"130.176.0.0/16",
|
|
||||||
"143.204.0.0/16",
|
|
||||||
"144.220.0.0/16",
|
|
||||||
"15.128.0.0/9",
|
|
||||||
"18.0.0.0/8",
|
|
||||||
"180.163.57.0/24",
|
|
||||||
"204.246.0.0/16",
|
|
||||||
"205.251.0.0/16",
|
|
||||||
"216.137.32.0/19",
|
|
||||||
"3.0.0.0/8",
|
|
||||||
"34.128.0.0/9",
|
|
||||||
"35.0.0.0/8",
|
|
||||||
"36.103.232.0/24",
|
|
||||||
"43.218.56.0/24",
|
|
||||||
"44.0.0.0/8",
|
|
||||||
"47.129.0.0/16",
|
|
||||||
"52.0.0.0/8",
|
|
||||||
"54.0.0.0/8",
|
|
||||||
"58.254.138.0/24",
|
|
||||||
"64.252.0.0/16",
|
|
||||||
"65.8.0.0/16",
|
|
||||||
"65.9.0.0/16",
|
|
||||||
"70.132.0.0/18",
|
|
||||||
"71.152.0.0/17",
|
|
||||||
"99.0.0.0/8"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"description": "cura ultimaker",
|
|
||||||
"domains": [
|
|
||||||
"ultimaker.com"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"188.114.98.0/23"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"description": "discord",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"104.16.0.0/12",
|
|
||||||
"108.177.14.207/32",
|
|
||||||
"138.128.140.240/28",
|
|
||||||
"142.250.150.207/32",
|
|
||||||
"142.251.1.207/32",
|
|
||||||
"162.159.128.0/20",
|
|
||||||
"172.64.0.0/14",
|
|
||||||
"173.194.0.0/16",
|
|
||||||
"18.165.140.0/25",
|
|
||||||
"188.114.0.0/16",
|
|
||||||
"204.11.56.48/32",
|
|
||||||
"209.85.233.207/32",
|
|
||||||
"23.227.38.74/32",
|
|
||||||
"34.0.0.0/7",
|
|
||||||
"64.233.160.0/21",
|
|
||||||
"66.22.192.0/18",
|
|
||||||
"74.125.128.0/17"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"description": "flibusta",
|
|
||||||
"domains": [
|
|
||||||
"flibusta.is"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"179.43.150.83/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"description": "facebook, instagram, oculus",
|
|
||||||
"domains": ["githubusercontent.com", "github.com"],
|
|
||||||
"networks": [
|
|
||||||
"185.199.0.0/16"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
{
|
|
||||||
"description": "google services (youtube, mail)",
|
|
||||||
"domains": [
|
|
||||||
"youtube.com",
|
|
||||||
"googlevideo.com",
|
|
||||||
"ytimg.com",
|
|
||||||
"youtu.be",
|
|
||||||
"ggpht.com",
|
|
||||||
"nhacmp3youtube.com",
|
|
||||||
"googleusercontent.com",
|
|
||||||
"googleapis.com",
|
|
||||||
"gstatic.com",
|
|
||||||
"google.ac", "google.ad", "google.ae", "google.al", "google.am", "google.as", "google.at", "google.az",
|
|
||||||
"google.ba", "google.be", "google.bf", "google.bg", "google.bi", "google.bj", "google.bs", "google.bt",
|
|
||||||
"google.by", "google.ca", "google.cat", "google.cd", "google.cf", "google.cg", "google.ch", "google.ci",
|
|
||||||
"google.cl", "google.cm", "google.cn", "google.co.ao", "google.co.bw", "google.co.ck", "google.co.cr",
|
|
||||||
"google.co.id", "google.co.il", "google.co.in", "google.co.jp", "google.co.ke", "google.co.kr", "google.co.ls",
|
|
||||||
"google.co.ma", "google.co.mz", "google.co.nz", "google.co.th", "google.co.tz", "google.co.ug", "google.co.uk",
|
|
||||||
"google.co.uz", "google.co.ve", "google.co.vi", "google.co.za", "google.co.zm", "google.co.zw", "google.com",
|
|
||||||
"google.com.af", "google.com.ag", "google.com.ai", "google.com.ar", "google.com.au", "google.com.bd", "google.com.bh",
|
|
||||||
"google.com.bn", "google.com.bo", "google.com.br", "google.com.bz", "google.com.co", "google.com.cu", "google.com.cy",
|
|
||||||
"google.com.do", "google.com.ec", "google.com.eg", "google.com.et", "google.com.fj", "google.com.gh", "google.com.gi",
|
|
||||||
"google.com.gt", "google.com.hk", "google.com.jm", "google.com.jo", "google.com.kh", "google.com.kw", "google.com.lb",
|
|
||||||
"google.com.ly", "google.com.mm", "google.com.mt", "google.com.mx", "google.com.my", "google.com.na", "google.com.ng",
|
|
||||||
"google.com.ni", "google.com.np", "google.com.om", "google.com.pa", "google.com.pe", "google.com.pg", "google.com.ph",
|
|
||||||
"google.com.pk", "google.com.pr", "google.com.py", "google.com.qa", "google.com.sa", "google.com.sb", "google.com.sg",
|
|
||||||
"google.com.sl", "google.com.sv", "google.com.tj", "google.com.tr", "google.com.tw", "google.com.ua", "google.com.uy",
|
|
||||||
"google.com.vc", "google.com.vn", "google.cv", "google.cz", "google.de", "google.dj", "google.dk", "google.dm",
|
|
||||||
"google.dz", "google.ee", "google.es", "google.fi", "google.fm", "google.fr", "google.ga", "google.ge", "google.gg",
|
|
||||||
"google.gl", "google.gm", "google.gp", "google.gr", "google.gy", "google.hn", "google.hr", "google.ht", "google.hu",
|
|
||||||
"google.ie", "google.im", "google.iq", "google.is", "google.it", "google.je", "google.jo", "google.kg", "google.ki",
|
|
||||||
"google.kz", "google.la", "google.li", "google.lk", "google.lt", "google.lu", "google.lv", "google.md", "google.me",
|
|
||||||
"google.mg", "google.mk", "google.ml", "google.mn", "google.ms", "google.mu", "google.mv", "google.mw", "google.ne",
|
|
||||||
"google.nl", "google.no", "google.nr", "google.nu", "google.pl", "google.pn", "google.ps", "google.pt", "google.ro",
|
|
||||||
"google.rs", "google.ru", "google.rw", "google.sc", "google.se", "google.sh", "google.si", "google.sk", "google.sn",
|
|
||||||
"google.so", "google.sr", "google.st", "google.td", "google.tg", "google.tl", "google.tm", "google.tn", "google.to",
|
|
||||||
"google.tt", "google.vg", "google.vu", "google.ws"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"188.43.61.0/24",
|
|
||||||
"157.240.252.0/23",
|
|
||||||
"87.245.216.0/24",
|
|
||||||
"85.249.244.0/23",
|
|
||||||
"213.221.56.0/27",
|
|
||||||
"104.154.0.0/15",
|
|
||||||
"104.196.0.0/14",
|
|
||||||
"104.237.160.0/19",
|
|
||||||
"104.237.160.0/19",
|
|
||||||
"107.167.160.0/19",
|
|
||||||
"107.178.192.0/18",
|
|
||||||
"108.170.192.0/18",
|
|
||||||
"108.177.0.0/17",
|
|
||||||
"108.59.80.0/20",
|
|
||||||
"130.211.0.0/16",
|
|
||||||
"136.124.0.0/15",
|
|
||||||
"136.22.0.0/16",
|
|
||||||
"142.250.0.0/15",
|
|
||||||
"146.148.0.0/17",
|
|
||||||
"152.65.0.0/16",
|
|
||||||
"162.120.128.0/17",
|
|
||||||
"162.216.148.0/22",
|
|
||||||
"162.222.176.0/21",
|
|
||||||
"172.110.32.0/21",
|
|
||||||
"172.217.0.0/16",
|
|
||||||
"172.253.0.0/16",
|
|
||||||
"173.194.0.0/16",
|
|
||||||
"173.255.112.0/20",
|
|
||||||
"178.66.83.0/24",
|
|
||||||
"192.158.28.0/22",
|
|
||||||
"192.178.0.0/15",
|
|
||||||
"193.186.4.0/24",
|
|
||||||
"195.95.178.0/24",
|
|
||||||
"199.192.112.0/22",
|
|
||||||
"199.223.232.0/21",
|
|
||||||
"199.36.154.0/23",
|
|
||||||
"199.36.156.0/24",
|
|
||||||
"207.223.160.0/20",
|
|
||||||
"208.117.224.0/19",
|
|
||||||
"208.65.152.0/22",
|
|
||||||
"208.68.108.0/22",
|
|
||||||
"208.81.188.0/22",
|
|
||||||
"209.85.0.0/16",
|
|
||||||
"216.239.32.0/19",
|
|
||||||
"216.58.192.0/19",
|
|
||||||
"216.73.80.0/20",
|
|
||||||
"23.236.48.0/20",
|
|
||||||
"23.251.128.0/19",
|
|
||||||
"34.0.0.0/7",
|
|
||||||
"57.140.192.0/18",
|
|
||||||
"64.15.112.0/20",
|
|
||||||
"64.233.0.0/16",
|
|
||||||
"66.102.0.0/20",
|
|
||||||
"66.22.228.0/23",
|
|
||||||
"66.249.64.0/19",
|
|
||||||
"70.32.128.0/19",
|
|
||||||
"72.14.192.0/18",
|
|
||||||
"74.125.0.0/16",
|
|
||||||
"8.34.208.0/20",
|
|
||||||
"8.35.192.0/20",
|
|
||||||
"8.8.4.0/24",
|
|
||||||
"8.8.8.0/24"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"description": "habrahabr",
|
|
||||||
"domains": [
|
|
||||||
"habr.com"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"178.248.237.68/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"description": "intel website",
|
|
||||||
"domains": [
|
|
||||||
"intel.com"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"23.42.171.108/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"description": "jetbrains market",
|
|
||||||
"domains": ["jetbrains.com"],
|
|
||||||
"networks": [
|
|
||||||
"108.157.229.0/24",
|
|
||||||
"18.245.46.0/24",
|
|
||||||
"18.238.243.0/24",
|
|
||||||
"52.85.49.0/24",
|
|
||||||
"3.160.150.0/24"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"description": "lostfilm",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"104.21.0.0/17"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"description": "notion",
|
|
||||||
"domains": [
|
|
||||||
"notion.so"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"104.18.39.102/32",
|
|
||||||
"172.64.148.154/32",
|
|
||||||
"208.103.161.0/30"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"description": "google & cloudflare public dns",
|
|
||||||
"domains": [],
|
|
||||||
"networks": [
|
|
||||||
"1.1.1.1/32",
|
|
||||||
"1.0.0.1/32",
|
|
||||||
"8.8.8.8/32",
|
|
||||||
"8.8.4.4/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"description": "rutor",
|
|
||||||
"domains": ["rutor.info"],
|
|
||||||
"networks": [
|
|
||||||
"193.46.255.29/32"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"description": "rutracker site & trackers",
|
|
||||||
"domains": [
|
|
||||||
"rutracker.org",
|
|
||||||
"rutracker.cc",
|
|
||||||
"t-ru.org"
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
"104.21.32.39/32",
|
|
||||||
"172.67.182.196/32",
|
|
||||||
"188.114.97.0/24",
|
|
||||||
"188.114.96.0/24",
|
|
||||||
"104.21.50.150/32",
|
|
||||||
"172.67.163.237/32",
|
|
||||||
"188.186.154.0/24"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"description": "www.snapeda.com",
|
|
||||||
"domains": ["snapeda.com"],
|
|
||||||
"networks": [
|
|
||||||
"104.20.16.0/20",
|
|
||||||
"172.66.144.0/20"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
class API extends Plugin
|
|
||||||
{
|
|
||||||
public function onInit(PluginContext $context): void
|
|
||||||
{
|
|
||||||
parent::onInit($context);
|
|
||||||
if (!isset($this->config["key"])) {
|
|
||||||
$this->generateNewKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = getallheaders();
|
|
||||||
|
|
||||||
if ($headers and isset($headers["X-Auth"]) and $headers["X-Auth"] == md5($this->config["key"])) {
|
|
||||||
$_SESSION["auth"] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generateNewKey(): string
|
|
||||||
{
|
|
||||||
$this->config["key"] = sha1(rand() . uniqid());
|
|
||||||
$this->saveConfig();
|
|
||||||
return $this->config["key"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey(): string
|
|
||||||
{
|
|
||||||
return $this->config["key"];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"class": "API",
|
|
||||||
"config": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
let key = await App.RPC.__invoke("api::getKey");
|
|
||||||
|
|
||||||
$("body").append("<span>API Key: " + key + "</span>")
|
|
||||||
})();
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
class Custom extends Plugin
|
|
||||||
{
|
|
||||||
public function onSync($remote_config)
|
|
||||||
{
|
|
||||||
if (!isset($remote_config["custom"])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->config = $remote_config["custom"];
|
|
||||||
$this->saveConfig();
|
|
||||||
|
|
||||||
$this->updateConfigFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateConfigFile()
|
|
||||||
{
|
|
||||||
$path = dirname(__DIR__, 2) . "/networks/custom.json";
|
|
||||||
$current_config = @file_get_contents($path);
|
|
||||||
$new_config = json_encode($this->config);
|
|
||||||
if($current_config !== $new_config) {
|
|
||||||
file_put_contents($path, $new_config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onInit(PluginContext $context): void
|
|
||||||
{
|
|
||||||
parent::onInit($context);
|
|
||||||
$this->updateConfigFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"class": "Custom",
|
|
||||||
"config": {
|
|
||||||
"description": "Custom routes",
|
|
||||||
"domains": [
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
|
|
||||||
(async function(){
|
|
||||||
await App.RPC.__invoke("custom::updateConfigFile")
|
|
||||||
})();
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class BindPlugin extends Plugin
|
|
||||||
{
|
|
||||||
public function restart(): string|bool|null
|
|
||||||
{
|
|
||||||
$selectedDomains = [];
|
|
||||||
|
|
||||||
$networks = (new NetworkConfigReader())->getConfigs();
|
|
||||||
|
|
||||||
//add new routes
|
|
||||||
foreach ($this->context->getConfig()["networks"] as $key) {
|
|
||||||
|
|
||||||
if (isset($networks[$key])) {
|
|
||||||
foreach ($networks[$key]["domains"] as $domain) {
|
|
||||||
$selectedDomains[] = $domain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$selectedDomains = array_unique($selectedDomains);
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
foreach ($selectedDomains as $domain) {
|
|
||||||
$data[] = $this->createForwardRecord($domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
file_put_contents($this->config["file"], implode("\n", $data));
|
|
||||||
|
|
||||||
|
|
||||||
return shell_exec($this->config["restart_cmd"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createForwardRecord($domain)
|
|
||||||
{
|
|
||||||
$fwd = implode(";", $this->config["forwarders"]) . ";";
|
|
||||||
return <<<TXT
|
|
||||||
zone "{$domain}" IN {
|
|
||||||
type forward;
|
|
||||||
forward only;
|
|
||||||
forwarders{{$fwd}};
|
|
||||||
};
|
|
||||||
TXT;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onServerStarted()
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSync($remote_config)
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"class": "BindPlugin",
|
|
||||||
"config": {
|
|
||||||
"restart_cmd": "/etc/init.d/named restart",
|
|
||||||
"file": "/var/bind/forward.dns",
|
|
||||||
"forwarders": ["8.8.8.8", "1.1.1.1"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
$("#buttons").append(`<button id="restart-bind">Restart named</button>`);
|
|
||||||
$("#restart-bind").click(function () {
|
|
||||||
|
|
||||||
const self = $(this);
|
|
||||||
self.prop("disabled", true);
|
|
||||||
(async function () {
|
|
||||||
try {
|
|
||||||
alert(await App.RPC.__invoke("named::restart"));
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => {
|
|
||||||
self.prop("disabled", false);
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Netsync extends Plugin
|
|
||||||
{
|
|
||||||
public function sync()
|
|
||||||
{
|
|
||||||
$host = $this->config["master"];
|
|
||||||
$key = $this->config["key"];
|
|
||||||
|
|
||||||
if (empty($key)) {
|
|
||||||
throw new RuntimeException("API key is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
$ch = curl_init("http://" . $host . "/rpc");
|
|
||||||
|
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
|
||||||
"jsonrpc" => "2.0",
|
|
||||||
"id" => "1",
|
|
||||||
"method" => "getConfig",
|
|
||||||
"params" => []
|
|
||||||
]));
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
"X-Auth: " . md5($key),
|
|
||||||
"Content-type: application/json"
|
|
||||||
]);
|
|
||||||
|
|
||||||
$output = curl_exec($ch);
|
|
||||||
try {
|
|
||||||
if ($err = curl_error($ch)) {
|
|
||||||
throw new RuntimeException("Failed to fetch remote API: " . $err);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
curl_close($ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
$header = @json_decode($output, true);
|
|
||||||
|
|
||||||
$remote_config = $header["result"] ?? null;
|
|
||||||
|
|
||||||
$networks = $remote_config["networks"] ?? null;
|
|
||||||
if ($remote_config === null or $networks === null) {
|
|
||||||
throw new RuntimeException("Response has invalid data");
|
|
||||||
}
|
|
||||||
|
|
||||||
$available = array_keys((new NetworkConfigReader())->getConfigs());
|
|
||||||
|
|
||||||
$remote_enabled = array_filter($networks, function ($e) use ($available) {
|
|
||||||
return in_array($e, $available);
|
|
||||||
});
|
|
||||||
$wrapper = $this->context->getConfig();
|
|
||||||
$local_enabled = $wrapper["networks"];
|
|
||||||
$diff = array_diff($remote_enabled, $local_enabled);
|
|
||||||
if (count($diff) > 0) {
|
|
||||||
$wrapper["networks"] = array_values($remote_enabled);
|
|
||||||
$wrapper->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$last_hash = $this->config["last_hash"] ?? "";
|
|
||||||
$current_hash = md5(json_encode($remote_config));
|
|
||||||
if ($last_hash != $current_hash) {
|
|
||||||
foreach ($this->context->getRPC()->getPlugins() as $plugin) {
|
|
||||||
/**
|
|
||||||
* @var IPluggable $plugin
|
|
||||||
*/
|
|
||||||
|
|
||||||
$plugin->onSync($remote_config);
|
|
||||||
}
|
|
||||||
$this->config["last_hash"] = $current_hash;
|
|
||||||
$this->saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"class": "Netsync",
|
|
||||||
"config": {
|
|
||||||
"master": "127.0.0.1:8001",
|
|
||||||
"key": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
$("#buttons").append(`<button id="sync">Force sync</button>`);
|
|
||||||
$("#sync").click(function () {
|
|
||||||
|
|
||||||
const self = $(this);
|
|
||||||
self.prop("disabled", true);
|
|
||||||
(async function () {
|
|
||||||
try {
|
|
||||||
alert(await App.RPC.__invoke("netsync::sync"));
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => {
|
|
||||||
location.reload();
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
class Openvpn extends Plugin
|
|
||||||
{
|
|
||||||
|
|
||||||
public function restart()
|
|
||||||
{
|
|
||||||
//restart ovpn
|
|
||||||
return shell_exec($this->config["restart_cmd"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function getRoutingConfig(): array
|
|
||||||
{
|
|
||||||
$networks = (new NetworkConfigReader())->getConfigs();
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
//add new routes
|
|
||||||
foreach ($this->context->getConfig() ["networks"] as $key) {
|
|
||||||
if (isset($networks[$key])) {
|
|
||||||
foreach ($networks[$key]["networks"] as $route) {
|
|
||||||
$parts = explode("/", $route);
|
|
||||||
$mask = long2ip(-1 << (32 - (int)$parts[1]));
|
|
||||||
$dst = $parts[0];
|
|
||||||
$data[] = "push \"route {$dst} {$mask}\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onServerStarted()
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSync($remote_config)
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"class": "Openvpn",
|
|
||||||
"config": {
|
|
||||||
"restart_cmd": "/etc/init.d/openvpn restart"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
(async function () {
|
|
||||||
$("#buttons").append(`<button id="restart-ovpn">Restart openvpn server</button>`);
|
|
||||||
$("#restart-ovpn").click(function () {
|
|
||||||
if (confirm("Are you sure?")) {
|
|
||||||
const self = $(this);
|
|
||||||
self.prop("disabled", true);
|
|
||||||
(async function () {
|
|
||||||
try {
|
|
||||||
alert(await App.RPC.__invoke("openvpn::restart"));
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => {
|
|
||||||
self.prop("disabled", false);
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
class QuaggaPlugin extends Plugin
|
|
||||||
{
|
|
||||||
|
|
||||||
const REM_PREFIX = "! routes from file ";
|
|
||||||
|
|
||||||
public function restart(): string
|
|
||||||
{
|
|
||||||
$configfile = $this->config["file"];
|
|
||||||
|
|
||||||
if (!file_exists($configfile)) {
|
|
||||||
throw new RuntimeException("Quagga config file not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
$networks = (new NetworkConfigReader())->getConfigs();
|
|
||||||
$routeParser = new RoutingTableReader();
|
|
||||||
$routes = $routeParser->getRoutes();
|
|
||||||
$defGatewayInterface = "";
|
|
||||||
$defGateway = "";
|
|
||||||
|
|
||||||
foreach ($routes as $route) {
|
|
||||||
if ($route["dst"] === "0.0.0.0/0") {
|
|
||||||
$defGatewayInterface = $route["dev"];
|
|
||||||
$defGateway = $route["gateway"];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$defGatewayInterface) {
|
|
||||||
throw new RuntimeException("Failed to detect default gateway interface");
|
|
||||||
}
|
|
||||||
|
|
||||||
$contents = file_get_contents($configfile);
|
|
||||||
$lines = explode("\n", $contents);
|
|
||||||
|
|
||||||
//remove existing routes
|
|
||||||
foreach ($lines as $key => $line) {
|
|
||||||
if (str_starts_with($line, self::REM_PREFIX) or str_starts_with($line, "ip route ") and str_contains($line . " ", $defGateway . " ")) {
|
|
||||||
unset($lines[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//add new routes
|
|
||||||
foreach ($this->context->getConfig()["networks"] as $key) {
|
|
||||||
$lines[] = self::REM_PREFIX . $key;
|
|
||||||
if (isset($networks[$key])) {
|
|
||||||
foreach ($networks[$key]["networks"] as $route) {
|
|
||||||
$lines[] = "ip route " . $route . " " . $defGateway;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($lines as $key => $line) {
|
|
||||||
if (trim($line) === "") {
|
|
||||||
unset($lines[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$backupFile = $configfile . ".sav";
|
|
||||||
|
|
||||||
unlink($backupFile);
|
|
||||||
rename($configfile, $backupFile);
|
|
||||||
file_put_contents($configfile, implode("\n", $lines));
|
|
||||||
|
|
||||||
sleep(10);
|
|
||||||
|
|
||||||
//restart zebra
|
|
||||||
return shell_exec($this->config["restart_cmd"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onServerStarted()
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSync($remote_config)
|
|
||||||
{
|
|
||||||
$this->restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"class": "QuaggaPlugin",
|
|
||||||
"config": {
|
|
||||||
"restart_cmd": "/etc/init.d/zebra restart",
|
|
||||||
"file": "/etc/quagga/zebra.conf"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import {App} from "/assets/App.js";
|
|
||||||
(async function () {
|
|
||||||
$("#buttons").append(`<button id="restart-quagga">Restart quagga</button>`);
|
|
||||||
$("#restart-quagga").click(function () {
|
|
||||||
if (confirm("Are you sure?")) {
|
|
||||||
const self = $(this);
|
|
||||||
self.prop("disabled", true);
|
|
||||||
(async function () {
|
|
||||||
try {
|
|
||||||
alert(await App.RPC.__invoke("quagga::restart"));
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => {
|
|
||||||
self.prop("disabled", false);
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Updates extends Plugin
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
public function check(): ?bool
|
|
||||||
{
|
|
||||||
$data = str_replace("=", "", @shell_exec("git --no-pager fetch --dry-run --porcelain --verbose 2>&1 | grep refs"));
|
|
||||||
$parts = explode(" ", trim($data));
|
|
||||||
if (count($parts) < 3) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $parts[0] != $parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function install(): string|bool|null
|
|
||||||
{
|
|
||||||
return @shell_exec("git --no-pager pull --verbose 2>&1");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"class": "Updates",
|
|
||||||
"config": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import {JSONRPC} from "/assets/jrpc.js";
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
$("#panel").prepend(`<div id="update-panel">Checking for updates...</div><hr>`);
|
|
||||||
let state = (await JSONRPC.__invoke("updates::check"));
|
|
||||||
if (state === null) {
|
|
||||||
$("#update-panel").html(`<span style="color:red;">Error checking updates</span>`);
|
|
||||||
} else if (state === false) {
|
|
||||||
$("#update-panel").html(`<span style="color:black;">There is no updates</span>`);
|
|
||||||
} else if (state === true) {
|
|
||||||
$("#update-panel").html(`<span style="color:green;">Some updates are available</span> <button>Update</button>`);
|
|
||||||
$("#update-panel button").click(async function () {
|
|
||||||
$("#panel").hide();
|
|
||||||
$("#loading").show().text("Installing updates...");
|
|
||||||
try {
|
|
||||||
alert(await JSONRPC.__invoke("updates::install"));
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => location.reload(), 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
12
restart.php
12
restart.php
|
|
@ -1,12 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
$memory = trim(shell_exec("free -b | grep Mem:"));
|
|
||||||
$memory = str_replace(" ", " ", $memory);
|
|
||||||
while (str_contains($memory, " ")) $memory = str_replace(" ", " ", $memory);
|
|
||||||
$items = explode(" ", $memory);
|
|
||||||
$available = intval($items[count($items) - 1]) / 1024 / 1024;
|
|
||||||
|
|
||||||
if ($available < 25) {
|
|
||||||
shell_exec("systemctl restart grass");
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once __DIR__ . "/loader.php";
|
|
||||||
$router = new WebRouter();
|
|
||||||
$router->handleRequest();
|
|
||||||
Loading…
Reference in New Issue