natpmp 0.8 → 0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +52 -0
- data/bin/natpmp +1 -5
- data/lib/natpmp.rb +26 -6
- data/lib/natpmp/version.rb +1 -1
- data/test/test_natpmp.rb +23 -6
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 504f5dbfbf0b924f579d4cc21c3329c415bb0d66
|
4
|
+
data.tar.gz: 2d29eb61c29f70a0876c5592781518c3514064e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 933f2b1277663de3fe5ac5c7110c53ab4ae65161ff1459ad1a1fe4e684c109719540c537647a822e2ffb11de01bde089d49ccadba8f165caefa602a29153e5f2
|
7
|
+
data.tar.gz: d776e773dc7c29c404d896a040120efa19634ba0e88b8d8250e57c94d0f1cfa825539226c1d5ef054fc406751d9f23ee1dbc038e50a67b567b0443ce94cf99be
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Ruby Gem for NAT-PMP
|
2
|
+
|
3
|
+
This is a client implementation of [NAT-PMP](http://tools.ietf.org/html/rfc6886)
|
4
|
+
|
5
|
+
For a server implementation suitable for Linux see [Stallone](https://github.com/tedjp/stallone)
|
6
|
+
|
7
|
+
Upon request NAT-PMP can open either a UDP or TCP port on the gateway and bidirectionally relay traffic to a specific external server.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
The GEM includes a command-line utility as well as Ruby classes and can be used in several ways
|
11
|
+
|
12
|
+
### To open a mapping from the command line
|
13
|
+
To open a mapping on specific ports use:
|
14
|
+
|
15
|
+
natpmp -p 1234
|
16
|
+
|
17
|
+
This command will hold the port open for the requested time, whereafter it _may_ be closed. To extend the mapping simply re-open it using the same port number.
|
18
|
+
|
19
|
+
### To run a command with a mapping
|
20
|
+
To run a command with specific port mappings:
|
21
|
+
|
22
|
+
natpmp -p 1234 'echo using the mapping && sleep 5'
|
23
|
+
|
24
|
+
The mapping will be held open until the command completes. The command string may contain the tokens %H, %P, %h and %p which will be substituted for the remote (uppercase) and local (lowercase) host (h) and ports (p). The ports can be automatically assigned by the command.
|
25
|
+
|
26
|
+
### Example Ruby Code
|
27
|
+
To open a port and run code using it:
|
28
|
+
|
29
|
+
require 'natpmp'
|
30
|
+
NATPMP.map 633, 13033, 10, :tcp do |map|
|
31
|
+
... # the mapping will be renewed until this exits
|
32
|
+
end
|
33
|
+
|
34
|
+
### Command Line Utility
|
35
|
+
The command line utility has the following options:
|
36
|
+
|
37
|
+
usage: natpmp [options] [command]
|
38
|
+
Open a port on a NAT-PMP gateway. Options:
|
39
|
+
-t, --type TYPE Type: tcp, udp (default: tcp)
|
40
|
+
-p, --port PORT Private port (default: auto)
|
41
|
+
--ttl TIME TTL if no command (default 7200 sec)
|
42
|
+
-P, --public PUBPORT External port (default: auto)
|
43
|
+
-v, --verbose Verbose
|
44
|
+
--version Version
|
45
|
+
In the command string the following substitutions will be made:
|
46
|
+
%p the local port
|
47
|
+
%h the local IP address
|
48
|
+
%P the gateway port
|
49
|
+
%H the gateway IP address
|
50
|
+
(Use %% to avoid this)
|
51
|
+
The mapping will be closed on completion of the command
|
52
|
+
-?, --help Display this screen
|
data/bin/natpmp
CHANGED
@@ -5,9 +5,6 @@ require 'natpmp/version'
|
|
5
5
|
require 'ostruct'
|
6
6
|
require 'optparse'
|
7
7
|
|
8
|
-
# TODO Extend the mapping if the command takes longer
|
9
|
-
# than the timeout.
|
10
|
-
|
11
8
|
types = [:tcp, :udp]
|
12
9
|
|
13
10
|
opts = OpenStruct.new(port: nil, type: :tcp, verbose: false, public: 0, ttl: 7200)
|
@@ -69,7 +66,7 @@ end
|
|
69
66
|
|
70
67
|
if ARGV.size > 0
|
71
68
|
command = ARGV.join(' ')
|
72
|
-
NATPMP.map opts.port, opts.public,
|
69
|
+
NATPMP.map opts.port, opts.public, nil, opts.type do |map|
|
73
70
|
command.gsub! /(?<!%)%p/, map.priv.to_s
|
74
71
|
command.gsub! /(?<!%)%h/, opts.localhost.to_s
|
75
72
|
command.gsub! /(?<!%)%P/, map.mapped.to_s
|
@@ -79,7 +76,6 @@ if ARGV.size > 0
|
|
79
76
|
system command
|
80
77
|
end
|
81
78
|
else
|
82
|
-
puts "noarg"
|
83
79
|
map = NATPMP.map opts.port, opts.public, opts.ttl, opts.type
|
84
80
|
end
|
85
81
|
|
data/lib/natpmp.rb
CHANGED
@@ -41,7 +41,7 @@ class NATPMP
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.verbose flag
|
44
|
+
def self.verbose flag
|
45
45
|
@verbose = flag
|
46
46
|
end
|
47
47
|
|
@@ -93,8 +93,8 @@ class NATPMP
|
|
93
93
|
@priv = priv
|
94
94
|
@pub = pub
|
95
95
|
@maxlife = maxlife
|
96
|
-
raise "Time must be >= 0" if maxlife < 0
|
97
96
|
@type = type
|
97
|
+
@renew = nil # Renewal thread
|
98
98
|
|
99
99
|
# These are filled in when a request is made
|
100
100
|
#
|
@@ -104,16 +104,18 @@ class NATPMP
|
|
104
104
|
|
105
105
|
# See section 3.3
|
106
106
|
def request!
|
107
|
-
rsp = NATPMP.send [0, OPCODE[@type], 0, @priv, @pub, @maxlife].pack("CCnnnN")
|
107
|
+
rsp = NATPMP.send [0, OPCODE[@type], 0, @priv, @pub, @maxlife||DEFAULT_LIFETIME].pack("CCnnnN")
|
108
108
|
(sssoe, priv, @mapped, @life) = rsp.unpack("x4NnnN")
|
109
109
|
raise "Port mismatch: requested #{@priv} received #{priv}" if @priv != priv
|
110
|
-
STDERR.puts "Mapped #{inspect}" if NATPMP.verbose
|
110
|
+
STDERR.puts "Mapped (at #{sssoe}) #{inspect}" if NATPMP.verbose?
|
111
|
+
schedule_renew! if @maxlife.nil?
|
111
112
|
end
|
112
113
|
|
113
114
|
# See section 3.4
|
114
115
|
def revoke!
|
116
|
+
@renew.exit if @renew
|
115
117
|
rsp = NATPMP.send [0, OPCODE[@type], 0, @priv, 0, 0].pack("CCnnnN")
|
116
|
-
STDERR.puts "Revoked #{inspect}" if NATPMP.verbose
|
118
|
+
STDERR.puts "Revoked #{inspect}" if NATPMP.verbose?
|
117
119
|
end
|
118
120
|
|
119
121
|
def inspect
|
@@ -122,7 +124,7 @@ class NATPMP
|
|
122
124
|
|
123
125
|
def self.map priv, pub, maxlife = DEFAULT_LIFETIME, type = :tcp, &block
|
124
126
|
|
125
|
-
map = NATPMP.new(priv, pub, maxlife, type)
|
127
|
+
map = NATPMP.new(priv, pub, block_given? ? nil: maxlife, type)
|
126
128
|
map.request!
|
127
129
|
if block_given?
|
128
130
|
begin
|
@@ -135,4 +137,22 @@ class NATPMP
|
|
135
137
|
return map
|
136
138
|
|
137
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# As per section 3.3 re-issue the request using the actual mapped port
|
144
|
+
def schedule_renew!
|
145
|
+
Thread.abort_on_exception = true
|
146
|
+
# As per section 3.3 re-issue the request using the actual mapped port
|
147
|
+
@renew = Thread.new @life do |life|
|
148
|
+
wait_time = life/2
|
149
|
+
STDERR.puts "Renewal in #{wait_time} seconds" if NATPMP.verbose?
|
150
|
+
sleep wait_time
|
151
|
+
rsp = NATPMP.send [0, OPCODE[@type], 0, @priv, @mapped, @life].pack("CCnnnN")
|
152
|
+
(sssoe, priv, @mapped, @life) = rsp.unpack("x4NnnN")
|
153
|
+
STDERR.puts "Renewed (at #{sssoe}) #{inspect}" if NATPMP.verbose?
|
154
|
+
schedule_renew!
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
138
158
|
end
|
data/lib/natpmp/version.rb
CHANGED
data/test/test_natpmp.rb
CHANGED
@@ -1,9 +1,26 @@
|
|
1
|
-
# Simple
|
2
|
-
#
|
1
|
+
# Simple tests
|
2
|
+
# Only work if the network gateway has NAT-PMP
|
3
|
+
# TODO Mock out the gateway object
|
3
4
|
#
|
4
|
-
require '
|
5
|
+
require 'test/unit'
|
6
|
+
require 'natpmp'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
class TestNATPMP < Test::Unit::TestCase
|
9
|
+
def test_gw
|
10
|
+
gw = NATPMP.GW
|
11
|
+
assert_match(/^(\d{1,3}\.){3}\d{1,3}$/, gw, "Return IPv4 address")
|
12
|
+
end
|
13
|
+
def test_basic
|
14
|
+
map = NATPMP.map 633, 13033, 30, :tcp
|
15
|
+
assert_equal(633, map.priv)
|
16
|
+
assert_equal(13033, map.pub)
|
17
|
+
assert_equal(30, map.life)
|
18
|
+
assert_equal(:tcp, map.type)
|
19
|
+
end
|
20
|
+
def test_block
|
21
|
+
m = NATPMP.map 633, 13033, 10, :tcp do |map|
|
22
|
+
assert_equal(NATPMP::DEFAULT_LIFETIME, map.life)
|
23
|
+
end
|
24
|
+
assert_nil(m)
|
25
|
+
end
|
9
26
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: natpmp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.9'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Townsend
|
@@ -18,6 +18,7 @@ executables:
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- README.md
|
21
22
|
- lib/natpmp.rb
|
22
23
|
- bin/natpmp
|
23
24
|
- lib/natpmp/version.rb
|