port_forwarder
A Dart library to manage router port forwarding rules using UPnP (Universal Plug and Play), NAT-PMP (Port Mapping Protocol), or NAT-PCP (Port Control Protocol).
This package allows applications to automatically configure port forwarding on compatible home routers, simplifying setup for P2P applications, game servers, or other services that need to be accessible from the external network.
Features
- Discover Gateways: Automatically find compatible routers on the local network supporting UPnP, NAT-PMP, or NAT-PCP.
- Manage Ports:
- Open (forward) TCP or UDP ports to the local machine.
- Close previously opened ports.
- Specify internal/external ports, lease duration, and descriptions.
- Check Mappings: Verify if a specific external port is currently mapped.
- Get IP Addresses: Retrieve the gateway's internal (LAN) and external (WAN) IP addresses.
- Protocol Selection: Choose which protocols (UPnP, PMP, PCP) to use for discovery.
Installation
-
Add this dependency to your project's
pubspec.yaml
file:dependencies: port_forwarder: ^1.0.0 # Or the latest version
-
Run
dart pub get
orflutter pub get
to install the package.
Usage
Here's a basic example demonstrating how to discover a gateway and manage a port:
import 'package:port_forwarder/port_forwarder.dart';
import 'dart:io';
const PortType _portType = PortType.tcp; // Or PortType.udp
const int _portNumber = 8080; // The external port you want to open
void main() async {
print("Discovering gateway...");
final Gateway? gateway = await Gateway.discover();
if (gateway == null) {
print("No compatible gateway found!");
return;
}
print("Gateway found!");
print("Gateway Type: ${gateway.type}");
print("Internal IP: ${gateway.internalAddress.address}");
try {
InternetAddress externalIp = await gateway.externalAddress;
print("External IP: ${externalIp.address}");
} on GatewayError catch(error) {
print("Could not retrieve external IP: $error");
}
try {
print("Opening port $_portNumber ($_portType)...");
await gateway.openPort(
protocol: _portType,
externalPort: _portNumber,
// internalPort: _portNumber, // Optional: defaults to externalPort
// portDescription: "My App Port", // Optional: description for the rule
// leaseDuration: 3600 // Optional: lease duration in seconds (0 = permanent)
);
print("Port $_portNumber opened successfully!");
} on GatewayError catch (error) {
print("Error opening port $_portNumber: $error");
return;
}
try {
final bool isMapped = await gateway.isMapped(protocol: _portType, externalPort: _portNumber);
if (isMapped) {
print("Port $_portNumber is confirmed to be mapped.");
} else {
print("Warning: Port $_portNumber is NOT reported as mapped after opening.");
}
} on GatewayError catch (error) {
print("Error checking port mapping for $_portNumber: $error");
}
try {
print("Closing port $_portNumber ($_portType)...");
await gateway.closePort(protocol: _portType, externalPort: _portNumber);
print("Port $_portNumber closed successfully!");
} on GatewayError catch (error) {
print("Error closing port $_portNumber: $error");
}
try {
final bool isMapped = await gateway.isMapped(protocol: _portType, externalPort: _portNumber);
if (!isMapped) {
print("Port $_portNumber is confirmed to be closed.");
} else {
print("Warning: Port $_portNumber is STILL reported as mapped after closing.");
}
} on GatewayError catch (error) {
print("Error checking port mapping for $_portNumber after closing: $error");
}
}
Libraries
- port_forwarder
- Support for doing something awesome.