Net::NAT::PMP - Poke holes in a router's NAT using the NAT-PMP protocol
use Net::NAT::PMP; $nat_pmp = new Net::NAT::PMP or die "Net::NAT::PMP: $!"; $external_address = $nat_pmp->external_address; die $nat_pmp->error unless defined $external_address; $external_port = $nat_pmp->create_mapping(40000); die $nat_pmp->error unless defined $external_port;
Net::NAT::PMP is a client for the NAT Port Mapping Protocol (NAT-PMP), which is currently an RFC draft. NAT-PMP is designed so that you can have rich network applications that can still work even behind your home router's NAT.
Creates a new Net::NAT::PMP object and tries to discover the address of the gateway (router). This currently only works on Mac OS X 10.5 and Linux. Other platforms must pass the $router_address parameter to new().
This queries the router for its external address. On success it returns the address as a string in dotted quad format. On failure it returns undef (call the error() method for details).
create_mapping($internal_port, $external_port, $lifetime_seconds, $udp)
This asks the router to open a up an external port and map it to $internal_port. The mapping will last for $lifetime_seconds. According to the RFC draft, the mapping should be re-requested when half the lifetime has elapsed. Net::NAT::PMP does not do this for you.
If $external_port is zero then the router will pick a port for you.
If $external_port is undef then Net::NAT::PMP will request that the external port be the same as the internal port.
If $lifetime_seconds is undef then the default of 3600 (one hour) is assumed.
If $lifetime_seconds and $external_port are both 0 then the mapping is destroyed instead of created. It's probably clearer to use the destroy_mapping() member function in this case.
If $udp is true then the mapping will be for UDP connection. If false then it will be for TCP connections.
create_mapping() will return the external port number. You shouldn't assume this will be the same as the port you requested. The router is free to choose a different port number if it doesn't like the requested port number for whatever reason.
On error, create_mapping() will return undef. When this happens you can check the error() method for details.
This will destroy a mapping.
This will return a string with details about the last error that occurred.
This barely implements the protocol. Specifically no attempt is made to retry or time out network transactions. This means that if you try to talk to the wrong IP address or your router doesn't support NAT-PMP, the external_address() and create_mapping() functions will hang. Yeah, that's weak. Patches are welcome.
This protocol relies on being able to get the IP address of the router. There appears to be no standard POSIX way to do this, so the code has to support each OS separately. Currently only Mac OS X and Linux are supported. Linux should be fairly stable since it is implemented by reading /proc/net/route which is what the route program itself does. The Mac OS X version, however, scrapes data from netstat which seems really fragile. It seems the way to do it natively involves interfacing with sysctl(). Again, patches are welcome.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Copyright (C) 2009 David Caldwell
David Caldwell <email@example.com>