Skip to content

Commit 3877abe

Browse files
author
root
committed
Sync code from standalone repo: Fix review issues (English, ENV, cleanup)
1 parent c4850d8 commit 3877abe

4 files changed

Lines changed: 72 additions & 99 deletions

File tree

mikrotik-nat-sync/README.md

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
![Platform](https://img.shields.io/badge/platform-Pelican%20Panel-orange.svg)
66
![AI](https://img.shields.io/badge/Created%20with-AI%20Gemini-brightgreen.svg)
77

8-
**MikroTik NAT Sync** — це плагін для автоматизації прокидання портів (Port Forwarding) між панеллю Pelican та маршрутизаторами MikroTik через REST API.
8+
**MikroTik NAT Sync**
99

1010
---
1111

@@ -24,53 +24,11 @@ Enable the REST API on your router to allow communication:
2424
```
2525
Note: We recommend creating a dedicated user with specific firewall permissions.
2626

27-
### 📦 Installation / Встановлення
27+
### 📦 Installation
2828

2929
**Method 1: Via Web Interface (Easiest)**
30-
1. Copy the direct link to the plugin ZIP archive:
31-
`https://github.com/avalon0077/mikrotik-nat-sync/archive/refs/heads/main.zip`
32-
2. In your Pelican Admin Panel, go to **Plugins** -> **Import**.
33-
3. Paste the URL or upload the downloaded ZIP file.
34-
4. Click **Install** and configure via the Gear icon.
30+
1. In your Pelican Admin Panel, go to **Plugins** -> **Import**.
31+
2. Paste the URL or upload the downloaded ZIP file.
32+
3. Click **Install** and configure via the Gear icon.
3533

36-
**Method 2: Manual (CLI)**
37-
1. Download and extract the archive to `/var/www/pelican/plugins/mikrotik-nat-sync`.
38-
2. Make sure the folder name is exactly `mikrotik-nat-sync`.
39-
3. Head to the **Plugins** page and click **Install**.
40-
41-
---
42-
43-
## 🇺🇦 Українською
44-
45-
### 🚀 Можливості
46-
* **Повна автоматизація**: Автоматично керує правилами DST-NAT на основі активних алокацій.
47-
48-
* **Безпека**: Список "Заборонених портів" для захисту системних сервісів.
49-
50-
* **Розумні теги**: Керує лише своїми правилами через коментар Pelican:.
51-
52-
* **Зручне налаштування**: Налаштуйте IP, логін, пароль та інтервали прямо в адмінці.
53-
54-
### 🛠 Налаштування MikroTik
55-
Увімкніть REST API для можливості віддаленого керування:
56-
57-
```Bash
58-
/ip service set www-ssl disabled=no port=9443
59-
```
60-
Порада: Створіть окремого користувача з правами на роботу лише з Firewall.
61-
62-
### 📦 Installation / Встановлення
63-
64-
**Спосіб 1: Через веб-інтерфейс (Найпростіший)**
65-
1. Скопіюйте пряме посилання на ZIP-архів плагіна:
66-
`https://github.com/avalon0077/mikrotik-nat-sync/archive/refs/heads/main.zip`
67-
2. В адмін-панелі Pelican перейдіть у **Plugins** -> **Import**.
68-
3. Вставте посилання або завантажте попередньо скачаний ZIP-файл.
69-
4. Натисніть **Install** та налаштуйте через іконку шестерні.
70-
71-
**Спосіб 2: Вручну (через консоль)**
72-
1. Скачайте та розпакуйте архів у папку `/var/www/pelican/plugins/mikrotik-nat-sync`.
73-
2. Переконайтеся, що папка називається саме `mikrotik-nat-sync`.
74-
3. Перейдіть на сторінку **Plugins** та натисніть **Install**.
75-
76-
>Developed with AI Assistance (Gemini) Розроблено за допомогою ШІ (Gemini)
34+
Developed with AI Assistance (Gemini)

mikrotik-nat-sync/plugin.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,5 @@
1111
"class": "MikroTikNATSyncPlugin",
1212
"panels": null,
1313
"panel_version": "1.0.0-beta32",
14-
"composer_packages": null,
15-
"meta": {
16-
"status": "enabled",
17-
"status_message": null
18-
}
19-
}
14+
"composer_packages": null
15+
}

mikrotik-nat-sync/src/Console/Commands/SyncMikrotikCommand.php

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,24 @@
99
class SyncMikrotikCommand extends Command
1010
{
1111
protected $signature = 'mikrotik:sync';
12-
protected $description = 'Синхронізація правил NAT з MikroTik з перевіркою заборонених портів';
12+
protected $description = 'Synchronize NAT rules with MikroTik checking for forbidden ports';
1313

1414
public function handle()
1515
{
1616
$this->info('Starting MikroTik Sync...');
1717

18-
$mk_ip = str_replace(['http://', 'https://'], '', env('MIKROTIK_IP'));
19-
$mk_port = env('MIKROTIK_PORT', '9080');
20-
$mk_user = env('MIKROTIK_USER');
21-
$mk_pass = env('MIKROTIK_PASS');
22-
$mk_interface = env('MIKROTIK_INTERFACE', 'ether1');
23-
24-
// Отримуємо список заборонених портів та перетворюємо в масив
25-
$forbidden_string = env('MIKROTIK_FORBIDDEN_PORTS', '');
18+
$mk_ip = str_replace(['http://', 'https://'], '', env('MIKROTIK_NAT_SYNC_IP'));
19+
$mk_port = env('MIKROTIK_NAT_SYNC_PORT', '9080');
20+
$mk_user = env('MIKROTIK_NAT_SYNC_USER');
21+
$mk_pass = env('MIKROTIK_NAT_SYNC_PASSWORD');
22+
$mk_interface = env('MIKROTIK_NAT_SYNC_INTERFACE', 'ether1');
23+
24+
// Get forbidden ports list and convert to array
25+
$forbidden_string = env('MIKROTIK_NAT_SYNC_FORBIDDEN_PORTS', '');
2626
$forbidden_ports = array_map('trim', explode(',', $forbidden_string));
2727

2828
if (!$mk_ip || !$mk_user || !$mk_pass) {
29-
$this->error('Налаштування MikroTik не заповнені!');
29+
$this->error('MikroTik settings are not configured!');
3030
return;
3131
}
3232

@@ -43,9 +43,9 @@ public function handle()
4343

4444
$whitelist = [];
4545
foreach ($active_servers as $srv) {
46-
// ПЕРЕВІРКА: чи порт не в списку заборонених
46+
// CHECK: if port is in forbidden list
4747
if (in_array((string)$srv->port, $forbidden_ports)) {
48-
$this->warn("Порт {$srv->port} для сервера {$srv->name} ЗАБОРОНЕНИЙ. Пропускаємо.");
48+
$this->warn("Port {$srv->port} for server {$srv->name} is FORBIDDEN. Skipping.");
4949
continue;
5050
}
5151

@@ -57,30 +57,47 @@ public function handle()
5757
try {
5858
$response = Http::withBasicAuth($mk_user, $mk_pass)->timeout(10)->get($url);
5959
if (!$response->successful()) {
60-
$this->error('Помилка API: ' . $response->body());
60+
$this->error('API Error: ' . $response->body());
6161
return;
6262
}
6363

6464
$existing_rules = [];
65-
foreach ($response->json() as $rule) {
65+
$rules_data = $response->json();
66+
67+
// Safety check if response is array
68+
if (!is_array($rules_data)) {
69+
$this->error('Invalid response format from MikroTik.');
70+
return;
71+
}
72+
73+
foreach ($rules_data as $rule) {
6674
if (isset($rule['comment']) && str_contains($rule['comment'], 'Pelican:')) {
67-
$key = ($rule['dst-port'] ?? '') . '-' . ($rule['protocol'] ?? 'tcp');
68-
$existing_rules[$key] = $rule['.id'];
75+
$dst_port = $rule['dst-port'] ?? '';
76+
$protocol = $rule['protocol'] ?? 'tcp';
77+
$key = $dst_port . '-' . $protocol;
78+
79+
// We need rule ID to delete it later if needed
80+
if (isset($rule['.id'])) {
81+
$existing_rules[$key] = $rule['.id'];
82+
}
6983
}
7084
}
7185

86+
// Remove old rules that are not in whitelist
7287
foreach ($existing_rules as $key => $id) {
7388
if (!isset($whitelist[$key])) {
7489
$this->warn("Deleting rule: $key");
7590
Http::withBasicAuth($mk_user, $mk_pass)->delete("$url/$id");
7691
}
7792
}
7893

94+
// Add new rules
7995
foreach ($whitelist as $key => $info) {
8096
if (!isset($existing_rules[$key])) {
8197
[$port, $proto] = explode('-', $key);
8298
$this->info("Adding rule: $key for {$info['name']}");
83-
Http::withBasicAuth($mk_user, $mk_pass)->put($url, [
99+
100+
$payload = [
84101
'chain' => 'dstnat',
85102
'action' => 'dst-nat',
86103
'to-addresses' => $info['ip'],
@@ -89,7 +106,9 @@ public function handle()
89106
'dst-port' => (string)$port,
90107
'in-interface' => $mk_interface,
91108
'comment' => "Pelican: {$info['name']} ({$info['uuid']})"
92-
]);
109+
];
110+
111+
Http::withBasicAuth($mk_user, $mk_pass)->put($url, $payload);
93112
}
94113
}
95114
$this->info('Sync Complete.');

mikrotik-nat-sync/src/MikroTikNATSyncPlugin.php

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function boot(Panel $panel): void
3535

3636
app()->booted(function () {
3737
$schedule = app(Schedule::class);
38-
$interval = env('MIKROTIK_SYNC_INTERVAL', 'everyFiveMinutes');
38+
$interval = env('MIKROTIK_NAT_SYNC_INTERVAL', 'everyFiveMinutes');
3939

4040
$schedule->command('mikrotik:sync')
4141
->{$interval}()
@@ -47,57 +47,57 @@ public function getSettingsForm(): array
4747
{
4848
return [
4949
TextInput::make('mk_ip')
50-
->label('IP MikroTik')
51-
->default(env('MIKROTIK_IP'))
50+
->label('MikroTik IP')
51+
->default(env('MIKROTIK_NAT_SYNC_IP'))
5252
->required(),
5353
TextInput::make('mk_port')
54-
->label('Порт REST API')
55-
->default(env('MIKROTIK_PORT', '9080'))
54+
->label('REST API Port')
55+
->default(env('MIKROTIK_NAT_SYNC_PORT', '9080'))
5656
->required(),
5757
TextInput::make('mk_user')
58-
->label('Користувач')
59-
->default(env('MIKROTIK_USER'))
58+
->label('Username')
59+
->default(env('MIKROTIK_NAT_SYNC_USER'))
6060
->required(),
6161
TextInput::make('mk_pass')
62-
->label('Пароль')
62+
->label('Password')
6363
->password()
6464
->revealable()
65-
->default(env('MIKROTIK_PASS')),
65+
->default(env('MIKROTIK_NAT_SYNC_PASSWORD')),
6666
TextInput::make('mk_interface')
67-
->label('Вхідний інтерфейс (WAN)')
68-
->default(env('MIKROTIK_INTERFACE', 'ether1'))
67+
->label('WAN Interface')
68+
->default(env('MIKROTIK_NAT_SYNC_INTERFACE', 'ether1'))
6969
->required(),
7070
TextInput::make('mk_forbidden_ports')
71-
->label('Заборонені порти (через кому)')
71+
->label('Forbidden Ports (comma separated)')
7272
->placeholder('22, 80, 443, 3306')
73-
->default(env('MIKROTIK_FORBIDDEN_PORTS')),
73+
->default(env('MIKROTIK_NAT_SYNC_FORBIDDEN_PORTS')),
7474
Select::make('mk_interval')
75-
->label('Інтервал синхронізації')
75+
->label('Sync Interval')
7676
->options([
77-
'everyMinute' => 'Щохвилини',
78-
'everyFiveMinutes' => 'Кожні 5 хвилин',
79-
'everyTenMinutes' => 'Кожні 10 хвилин',
80-
'hourly' => 'Щогодини',
77+
'everyMinute' => 'Every Minute',
78+
'everyFiveMinutes' => 'Every 5 Minutes',
79+
'everyTenMinutes' => 'Every 10 Minutes',
80+
'hourly' => 'Hourly',
8181
])
82-
->default(env('MIKROTIK_SYNC_INTERVAL', 'everyFiveMinutes'))
82+
->default(env('MIKROTIK_NAT_SYNC_INTERVAL', 'everyFiveMinutes'))
8383
->required(),
8484
];
8585
}
8686

8787
public function saveSettings(array $data): void
8888
{
8989
$this->writeToEnvironment([
90-
'MIKROTIK_IP' => $data['mk_ip'],
91-
'MIKROTIK_PORT' => $data['mk_port'],
92-
'MIKROTIK_USER' => $data['mk_user'],
93-
'MIKROTIK_PASS' => $data['mk_pass'],
94-
'MIKROTIK_INTERFACE' => $data['mk_interface'],
95-
'MIKROTIK_SYNC_INTERVAL' => $data['mk_interval'],
96-
'MIKROTIK_FORBIDDEN_PORTS' => $data['mk_forbidden_ports'],
90+
'MIKROTIK_NAT_SYNC_IP' => $data['mk_ip'],
91+
'MIKROTIK_NAT_SYNC_PORT' => $data['mk_port'],
92+
'MIKROTIK_NAT_SYNC_USER' => $data['mk_user'],
93+
'MIKROTIK_NAT_SYNC_PASSWORD' => $data['mk_pass'],
94+
'MIKROTIK_NAT_SYNC_INTERFACE' => $data['mk_interface'],
95+
'MIKROTIK_NAT_SYNC_INTERVAL' => $data['mk_interval'],
96+
'MIKROTIK_NAT_SYNC_FORBIDDEN_PORTS' => $data['mk_forbidden_ports'],
9797
]);
9898

9999
Notification::make()
100-
->title('Налаштування збережено')
100+
->title('Settings saved successfully')
101101
->success()
102102
->send();
103103
}

0 commit comments

Comments
 (0)