port_forwarder

Pub Version Repository

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

  1. Add this dependency to your project's pubspec.yaml file:

    dependencies:
      port_forwarder: ^1.0.0 # Or the latest version
    
  2. Run dart pub get or flutter 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.