diff --git a/app/bot.php b/app/bot.php index eb30db9..0b88294 100644 --- a/app/bot.php +++ b/app/bot.php @@ -135,6 +135,9 @@ class Bot case preg_match('~^/changeAllowedIps (?P\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m): $this->changeAllowedIps(...explode('_', $m['arg'])); break; + case preg_match('~^/calc (?P\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m): + $this->calc(...explode('_', $m['arg'])); + break; case preg_match('~^/changeIps (?P\w+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m): $this->changeIps(...explode('_', $m['arg'])); break; @@ -1497,9 +1500,68 @@ DNS-over-HTTPS with IP: $this->subnet($page); } + public function calc($page) + { + $r = $this->send( + $this->input['chat'], + "@{$this->input['username']} enter like '10.0.0.0/24, -10.0.0.5/32'", + $this->input['message_id'], + reply: 'enter like \'10.0.0.0/24, -10.0.0.5/32\'', + ); + $_SESSION['reply'][$r['result']['message_id']] = [ + 'start_message' => $this->input['message_id'], + 'start_callback' => $this->input['callback_id'], + 'callback' => 'calcSubnet', + 'args' => [$page], + ]; + } + + public function calcSubnet($text) + { + $text = explode(',', $text); + $text = array_map(fn ($e) => trim($e), $text); + if (!empty($text)) { + foreach ($text as $k => $v) { + if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}~', $v)) { + $include[] = $v; + } + if (preg_match('~^-(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2})~', $v, $m)) { + $exclude[] = $m[1]; + } + } + } + if (!empty($include)) { + foreach ($include as $k => $v) { + $t = explode('/', $v); + $include[$k] = [ip2long($t[0]), ip2long($t[0]) + (1 << (32 - $t[1])) - 1]; + } + if (!empty($exclude)) { + foreach ($exclude as $k => $v) { + $t = explode('/', $v); + $exclude[$k] = [ip2long($t[0]), ip2long($t[0]) + (1 << (32 - $t[1])) - 1]; + } + } + $c = new Calc(); + $r = $c->prepare($include, $exclude ?: []); + if (!empty($r)) { + $t = []; + foreach ($r as $k => $v) { + $t = array_merge($t, $c->toCIDR($v[0], $v[1])); + } + $this->send($this->input['chat'], '
' . implode(', ', $t) . '
'); + } + } + } + public function subnet($page = 0, $count = 5) { $text = "Menu -> Wireguard -> " . $this->i18n('listSubnet') . "\n"; + $data[] = [ + [ + 'text' => $this->i18n('calc'), + 'callback_data' => "/calc $page", + ], + ]; $data[] = [ [ 'text' => $this->i18n('add'), diff --git a/app/calc.php b/app/calc.php new file mode 100644 index 0000000..1775812 --- /dev/null +++ b/app/calc.php @@ -0,0 +1,79 @@ + $a[1] + 1) { + $tmp = [$a, $b]; + } elseif ($b[1] <= $a[1]) { + $tmp = [$a]; + } else { + $tmp = [[$a[0], $b[1]]]; + } + return array_filter($tmp); + } + + public function substract(array $a, array $b): array + { + if ($b[0] > $a[1] || $b[1] < $a[0]) { + return [$a]; + } elseif ($b[0] <= $a[0] && $b[1] >= $a[1]) { + return []; + } elseif ($b[0] > $a[0] && $b[1] < $a[1]) { + return [[$a[0], $b[0] - 1], [$b[1] + 1, $a[1]]]; + } elseif ($b[0] <= $a[0]) { + return [$b[1] + 1, $a[1]]; + } else { + return [$a[0], $b[1] - 1]; + } + } + + public function alignment(array $arr): array + { + usort($arr, fn ($a, $b) => $a[0] <=> $b[0]); + $tmp = [[]]; + foreach ($arr as $k => $v) { + $t = array_pop($tmp); + $tmp = array_merge($tmp, $this->merge($t, $v)); + } + return $tmp; + } + + public function prepare(array $include, array $exclude): array + { + $include = $this->alignment($include); + if (!empty($exclude)) { + $tmp = []; + $exclude = $this->alignment($exclude); + foreach ($exclude as $k => $v) { + foreach ($include as $i => $j) { + $tmp = array_merge($tmp, $this->substract($j, $v)); + } + $d = array_filter($tmp); + } + return $tmp; + } + return $include; + } + + public function toCIDR(int $a, int $b) + { + $diff = $b - $a + 1; + if ($diff > 1) { + for ($i = 0; $i <= 32; $i++) { + if ($diff / (1 << $i) < 1) { + break; + } + } + $tmp[] = long2ip($a) . "/" . (32 - $i + 1); + $new = $a + (1 << ($i - 1)); + if ($new <= $b) { + $tmp = array_merge($tmp, $this->toCIDR($new, $b)); + } + } else { + $tmp[] = long2ip($a) . "/32"; + } + return $tmp; + } +} diff --git a/app/i18n.php b/app/i18n.php index 93dd3c4..776d26c 100644 --- a/app/i18n.php +++ b/app/i18n.php @@ -217,4 +217,8 @@ $i = [ 'en' => 'AllowedIPs', 'ru' => 'AllowedIPs', ], + 'calc' => [ + 'en' => 'calc CIDR', + 'ru' => 'calc CIDR', + ], ]; diff --git a/app/index.php b/app/index.php index b071670..51e85b4 100644 --- a/app/index.php +++ b/app/index.php @@ -6,6 +6,7 @@ require __DIR__ . '/timezone.php'; require __DIR__ . '/config.php'; if ('POST' == $_SERVER['REQUEST_METHOD'] && $_GET['k'] == $c['key']) { // require __DIR__ . '/debug.php'; + require __DIR__ . '/calc.php'; require __DIR__ . '/bot.php'; require __DIR__ . '/i18n.php'; $bot = new Bot($c['key'], $i);