offbynull / portmapper

Java library that maps ports on NAT-enabled routers (supported protocols: UPnP-IGD/NAT-PMP/PCP).
Apache License 2.0
88 stars 17 forks source link

Port Mapper

Portmapper logo

The Port Mapper project is a Java library that allows you to forward ports on NAT-enabled routers. Originally developed as part of the Peernetic project, Port Mapper has several distinct advantages over existing Java libraries that provide port forwarding functionality.

Table of Contents

Quick-start Guide

Port Mapper requires Java7 or later. In your Maven POM, add "portmapper" as a dependency.

<dependency>
    <groupId>com.offbynull.portmapper</groupId>
    <artifactId>portmapper</artifactId>
    <version>2.0.6</version>
</dependency>

The following example attempts to forward some external port (55555 preferred) to internal port 12345 on the first port forwarding device it finds.

// Start gateways
Gateway network = NetworkGateway.create();
Gateway process = ProcessGateway.create();
Bus networkBus = network.getBus();
Bus processBus = process.getBus();

// Discover port forwarding devices and take the first one found
List<PortMapper> mappers = PortMapperFactory.discover(networkBus, processBus);
PortMapper mapper = mappers.get(0);

// Map internal port 12345 to some external port (55555 preferred)
//
// IMPORTANT NOTE: Many devices prevent you from mapping ports that are <= 1024
// (both internal and external ports). Be mindful of this when choosing which
// ports you want to map.
MappedPort mappedPort = mapper.mapPort(PortType.TCP, 12345, 55555, 60);
System.out.println("Port mapping added: " + mappedPort);

// Refresh mapping half-way through the lifetime of the mapping (for example,
// if the mapping is available for 40 seconds, refresh it every 20 seconds)
while(!shutdown) {
    mappedPort = mapper.refreshPort(mappedPort, mappedPort.getLifetime());
    System.out.println("Port mapping refreshed: " + mappedPort);
    Thread.sleep(mappedPort.getLifetime() / 2L * 1000L);
}

// Unmap port 12345
mapper.unmapPort(mappedPort);

// Stop gateways
networkBus.send(new KillNetworkRequest());
processBus.send(new KillProcessRequest()); // can kill this after discovery

FAQ

What if I want to discover only one type of port forwarding device?

You can use the identify method on PortMapper implementations directly.

List<UpnpIgdPortMapper> upnpIgdMappers = UpnpIgdPortMapper.identify(networkBus);

List<NatPmpPortMapper> natPmpMappers = NatPmpPortMapper.identify(networkBus, processBus, additionalIps);

List<PcpPortMapper> pcpMappers = PcpPortMapper.identify(networkBus, processBus, additionalIps);

How is this library considered light-weight?

Several reasons. The Port Mapper project

  1. has very few dependencies on third-party libraries.
  2. doesn't require any special parsing libraries (e.g. XML/SOAP/HTTP/etc..) -- all parsing is done as US-ASCII text.
  3. doesn't require any special networking libraries (e.g. Netty/MINA/etc..) -- all networking is done through standard NIO.
  4. doesn't make use of regular expressions.

Because of this, the code should be easily portable to other languages -- especially languages that don't have the same robust ecosystem that Java does.

How is this library considered fault-tolerant?

The Port Mapper project aims to be resilient when it comes to faulty responses, especially when using UPnP-IGD. The code

  1. parses XML as text, based on patterns/heuristics (works around issues such as invalid XML syntax/invalid XML structure/incorrect capitalization/etc..).
  2. attempts requests multiple times when the device responds with a failure (works around temporary network failure and other temporary hiccups that cause bad response codes).

How does this library discover NAT-PMP and PCP gateway devices?

Unfortunately, Java doesn't provide a built-in way to grab gateway addresses from the OS, nor does it allow you to do ICMP probing to find devices on path (e.g. set TTL to 1 and ping, the first device is very likely the gateway). As such, the Port Mapper project makes use of various OS-specific commands to find gateway addresses. You can find out which commands are used by looking through the source code.

Does this library support PCP authentication and/or UPnP-IGD device protection?

Not at this time. Support may be added in the future.

Does this library support unsolicited PCP ANNOUNCEs or UPnP eventing?

Not at this time. Version 1 did support unsolicited PCP ANNOUNCEs, but it has since been removed because no devices seem to support it. If you're worried about not being notified of lost mappings, just make sure you refresh more often so that you catch the problem early (e.g. every 5 or 10 minutes).

What alternatives are available?

Alternatives to Port Mapper include:

If you know of any other projects please let me know and I'll update this section.

Change Log

Template adapted from http://keepachangelog.com/

All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning.

[Unreleased][unreleased]

[2.0.6] - 2023-01-05

[2.0.5] - 2016-11-18

[2.0.4] - 2016-07-26

[2.0.3] - 2016-07-15

[2.0.2] - 2016-07-06

[2.0.1] - 2016-06-25

[2.0.0] - 2016-01-17

[1.0.0] - 2014-06-24