natpmp 0.8 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|