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.
- Tested on all major platforms: Android, Windows, Linux, and Mac
- Supports UPnP-IGD (Universal Plug-and-Play Internet Gateway Device) -- both IGD v1.0 and IGD v2.0 services
- Supports NAT-PMP (Network Address Traversal Port Mapping Protocol)
- Supports PCP (Port Control Protocol)
- Supports both IPv4 and IPv6
- Fault-tolerant -- works around malformed responses and faulty devices
- Light-weight -- very few third-party dependencies and easy to port to other languages
- Quick-start Guide
- FAQ
- What if I want to discover only one type of port forwarding device?
- How is this library considered light-weight?
- How is this library considered fault-tolerant?
- How does this library discover NAT-PMP and PCP gateway devices?
- Does this library support PCP authentication and/or UPnP-IGD device protection?
- Does this library support unsolicited PCP ANNOUNCEs or UPnP eventing?
- What alternatives are available?
- Change Log
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
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);
Several reasons. The Port Mapper project
- has very few dependencies on third-party libraries.
- doesn't require any special parsing libraries (e.g. XML/SOAP/HTTP/etc..) -- all parsing is done as US-ASCII text.
- doesn't require any special networking libraries (e.g. Netty/MINA/etc..) -- all networking is done through standard NIO.
- 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.
The Port Mapper project aims to be resilient when it comes to faulty responses, especially when using UPnP-IGD. The code
- parses XML as text, based on patterns/heuristics (works around issues such as invalid XML syntax/invalid XML structure/incorrect capitalization/etc..).
- 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).
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.
Not at this time. Support may be added in the future.
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).
Alternatives to Port Mapper include:
If you know of any other projects please let me know and I'll update this section.
Template adapted from http://keepachangelog.com/
All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning.
- OTHER: Automatic module name added (thank you to @hendrikebbers)
- FIXED: NetworkRunnable crash when getting IP addresses for inactive interface
- FIXED: Race condition where some stdout output wouldn't be received from a process because it was sent just before termination
- FIXED: Process output now include stderr output
- FIXED: Attempt to filter out bad NAT-PMP/PCP gateway IP addresses -- loopback (e.g. 127.0.0.1), any address (e.g. 0.0.0.0), and multicast addresses are now filtered out
- FIXED: PCP port signed/unsigned integer bug fixed
- FIXED: NAT-PMP result code signed/unsigned integer bug fixed
- OTHER: Logging tweaked for NetworkGateway and ProcessGateway
- FIXED: \r\n newlines removed from UPnP-IGD request XMLs
- FIXED: namespace and encoding style URLs fixed for UPnP-IGD request XMLs
- OTHER: License updated from LGPL3 to Apache2
- FIXED: Issue when getting bad unexpected HTTP version in response
- CHANGED: Refactored API and backend
- ADDED: UPnP-IGD IPv6 firewall service support
- FIXED: Issue when scraping IPv4 address from output
- FIXED: Issue with Macs getting SocketExceptions on PCP discovery
- OTHER: Updated README
- OTHER: New logo made in Inkscape
- Initial release.