diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml
new file mode 100644
index 0000000..91f9558
--- /dev/null
+++ b/.idea/deviceManager.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index db209aa..d3f0221 100644
--- a/README.md
+++ b/README.md
@@ -70,11 +70,13 @@ Set bidirectional bandwidth limits for a peer (controls both upload and download
}
```
*Note: 125000 bytes/s = 1000 kbps = 1 Mbps*
+*Use -1 for unlimited speed*
**Common Speed Conversions:**
- 125 KB/s = 1 Mbps
- 1,250 KB/s = 10 Mbps
- 12,500 KB/s = 100 Mbps
+- -1 = Unlimited
#### `POST /api/peers/data-cap`
Set total data usage limits for a peer using iptables quota rules.
@@ -87,11 +89,13 @@ Set total data usage limits for a peer using iptables quota rules.
}
```
*Note: 1073741824 bytes = 1 GB*
+*Use -1 for unlimited data*
**Common Data Conversions:**
- 1 GB = 1,073,741,824 bytes
- 10 GB = 10,737,418,240 bytes
- 100 GB = 107,374,182,400 bytes
+- -1 = Unlimited
#### `POST /api/peers/config`
Retrieve peer configuration (currently not implemented - returns 404).
diff --git a/lib/services/server_service.dart b/lib/services/server_service.dart
index 0d09e32..5c38ede 100644
--- a/lib/services/server_service.dart
+++ b/lib/services/server_service.dart
@@ -4,7 +4,7 @@ import 'package:waylume_server/core/utils.dart';
class ServerService {
static Future registerServer() async {
- String ip = await getWanIp();
+ String ip = "${await getWanIp()}:${fromEnivronment("EXTERNAL_PORT") ?? "3000"}";
var existsCheck = await SUPABASE_CLIENT
.from("waylume_servers")
diff --git a/lib/wireguard/traffic_control.dart b/lib/wireguard/traffic_control.dart
index 13d3780..f39b171 100644
--- a/lib/wireguard/traffic_control.dart
+++ b/lib/wireguard/traffic_control.dart
@@ -3,6 +3,14 @@ import 'dart:io';
class TrafficControlService {
static Future setSpeedLimit(String peerIP, int bytesPerSecond) async {
final mark = _getMarkForIP(peerIP);
+
+ // Handle unlimited speed (-1)
+ if (bytesPerSecond == -1) {
+ print('Removing speed limit for peer $peerIP (unlimited)');
+ await _removeSpeedLimit(peerIP, mark);
+ return;
+ }
+
final kbps = (bytesPerSecond * 8 / 1000).round(); // Convert bytes/s to kbps
print('Setting speed limit for peer $peerIP to ${bytesPerSecond} bytes/s (${kbps}kbps, mark: $mark)');
@@ -125,8 +133,18 @@ class TrafficControlService {
}
static Future setDataCap(String peerIP, int quotaBytes) async {
+ // Handle unlimited data cap (-1)
+ if (quotaBytes == -1) {
+ print('Removing data cap for peer $peerIP (unlimited)');
+ await _removeDataCap(peerIP);
+ return;
+ }
+
print('Setting data cap for peer $peerIP to $quotaBytes bytes');
+ // Remove existing data cap rules first
+ await _removeDataCap(peerIP);
+
await _runIptablesCommand(['-I', 'FORWARD', '-s', peerIP, '-m', 'quota', '--quota', quotaBytes.toString(), '-j', 'ACCEPT']);
await _runIptablesCommand(['-I', 'FORWARD', '-d', peerIP, '-m', 'quota', '--quota', quotaBytes.toString(), '-j', 'ACCEPT']);
await _runIptablesCommand(['-A', 'FORWARD', '-s', peerIP, '-j', 'DROP']);
@@ -157,6 +175,74 @@ class TrafficControlService {
return 'eth0';
}
+ static Future _removeSpeedLimit(String peerIP, int mark) async {
+ final uploadMark = mark;
+ final downloadMark = mark + 1000;
+
+ print('Removing speed limit rules for $peerIP...');
+
+ // Remove iptables mangle rules
+ try {
+ await _runIptablesCommand(['-t', 'mangle', '-D', 'POSTROUTING', '-s', peerIP, '-j', 'MARK', '--set-mark', uploadMark.toString()]);
+ } catch (e) { /* Rule doesn't exist, ignore */ }
+ try {
+ await _runIptablesCommand(['-t', 'mangle', '-D', 'FORWARD', '-d', peerIP, '-j', 'MARK', '--set-mark', downloadMark.toString()]);
+ } catch (e) { /* Rule doesn't exist, ignore */ }
+
+ // Remove tc classes and filters
+ final outgoingInterface = await _detectOutgoingInterface();
+
+ try {
+ await _runTcCommand(['filter', 'del', 'dev', outgoingInterface, 'protocol', 'ip', 'parent', '2:', 'prio', '1', 'handle', uploadMark.toString(), 'fw']);
+ } catch (e) { /* Filter doesn't exist, ignore */ }
+ try {
+ await _runTcCommand(['filter', 'del', 'dev', 'wg0', 'protocol', 'ip', 'parent', '1:', 'prio', '1', 'handle', downloadMark.toString(), 'fw']);
+ } catch (e) { /* Filter doesn't exist, ignore */ }
+
+ try {
+ await _runTcCommand(['class', 'del', 'dev', outgoingInterface, 'classid', '2:$uploadMark']);
+ } catch (e) { /* Class doesn't exist, ignore */ }
+ try {
+ await _runTcCommand(['class', 'del', 'dev', 'wg0', 'classid', '1:$downloadMark']);
+ } catch (e) { /* Class doesn't exist, ignore */ }
+
+ print('Speed limit removed for $peerIP');
+ }
+
+ static Future _removeDataCap(String peerIP) async {
+ print('Removing data cap rules for $peerIP...');
+
+ // Remove quota rules (these are harder to target specifically, so we try common patterns)
+ try {
+ await _runIptablesCommand(['-D', 'FORWARD', '-s', peerIP, '-j', 'DROP']);
+ } catch (e) { /* Rule doesn't exist, ignore */ }
+ try {
+ await _runIptablesCommand(['-D', 'FORWARD', '-d', peerIP, '-j', 'DROP']);
+ } catch (e) { /* Rule doesn't exist, ignore */ }
+
+ // Remove quota rules by flushing and re-adding basic rules
+ // This is a bit aggressive but necessary since quota rules are hard to target specifically
+ try {
+ final result = await Process.run('iptables', ['-S', 'FORWARD']);
+ if (result.exitCode == 0) {
+ final lines = result.stdout.toString().split('\n');
+ for (final line in lines) {
+ if (line.contains(peerIP) && line.contains('quota')) {
+ // Extract the rule and convert -A to -D to delete it
+ final deleteRule = line.replaceFirst('-A', '-D');
+ try {
+ await Process.run('iptables', deleteRule.split(' ').skip(1).toList());
+ } catch (e) { /* Ignore individual failures */ }
+ }
+ }
+ }
+ } catch (e) {
+ print('Failed to remove specific quota rules: $e');
+ }
+
+ print('Data cap removed for $peerIP');
+ }
+
static Future _runIptablesCommand(List args) async {
final command = 'iptables ${args.join(' ')}';
print('Executing: $command');