openvpn-frr-template/connect.php

94 lines
2.6 KiB
PHP

#!/usr/bin/php
<?php
function is_subnet_overlaps($subnet, $candidate)
{
$parts = explode("/", $subnet);
$prefix = $parts[1];
$subnet_first = ip2long($parts[0]);
$candidate_prefix = explode("/", $candidate)[1];
$count = pow(2, 32 - (int)$prefix);
$subnet_last = $subnet_first + $count - 1;
$test_ip = ip2long(explode("/", $candidate)[0]);
return $test_ip >= $subnet_first and $test_ip <= $subnet_last and $candidate_prefix > $prefix;
}
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";
}
}
}
}
try {
if (!isset($argv[1])) {
throw new RuntimeException("Output config is not set");
}
$config = [];
$reader = new RoutingTableReader();
$routes = [];
$overlapped = [];
foreach ($reader->getRoutes() as $route) {
if ($route["dst"] == "0.0.0.0/0") {
continue;
}
$routes[] = $route;
}
foreach ($routes as $i => $master) {
if (in_array($master, $overlapped)) {
continue;
}
foreach ($routes as $j => $slave) {
if ($i == $j or in_array($slave, $overlapped)) {
continue;
}
if (is_subnet_overlaps($master["dst"], $slave["dst"])) {
$overlapped[] = $slave;
}
}
}
$subnets = [];
foreach ($routes as $i => $master) {
if (in_array($master, $overlapped)) {
continue;
}
$subnets[] = $master["dst"];
}
foreach ($subnets as $route) {
$parts = explode("/", $route);
$mask = long2ip(-1 << (32 - (int)$parts[1]));
$dst = $parts[0];
$config[] = "push \"route {$dst} {$mask}\"";
}
$outfile = $argv[1];
file_put_contents($outfile, implode("\n", $config));
} catch (Exception $e) {
echo "\nError:" . $e->getMessage() . "\n";
exit(1);
}
exit(0);