Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
8d8b42f9be |
1 changed files with 18 additions and 1 deletions
|
@ -70,8 +70,17 @@ module NatPMP
|
||||||
def initialize(@gateway_ip : String, autoconnect : Bool = true)
|
def initialize(@gateway_ip : String, autoconnect : Bool = true)
|
||||||
# The specification is IPV4 only!
|
# The specification is IPV4 only!
|
||||||
@socket = UDPSocket.new(Socket::Family::INET)
|
@socket = UDPSocket.new(Socket::Family::INET)
|
||||||
|
# A given host may have more than one independent
|
||||||
|
# NAT-PMP client running at the same time, and address announcements
|
||||||
|
# need to be available to all of them. Clients should therefore set
|
||||||
|
# the SO_REUSEPORT option or equivalent in order to allow other
|
||||||
|
# processes to also listen on port 5350.
|
||||||
@socket.reuse_port = true
|
@socket.reuse_port = true
|
||||||
@socket.reuse_address = true
|
@socket.reuse_address = true
|
||||||
|
# Additionally, implementers
|
||||||
|
# have encountered issues when one or more processes on the same device
|
||||||
|
# listen to port 5350 on *all* addresses. Clients should therefore
|
||||||
|
# bind specifically to 224.0.0.1:5350, not to 0.0.0.0:5350.
|
||||||
@socket.bind 5350
|
@socket.bind 5350
|
||||||
if autoconnect
|
if autoconnect
|
||||||
connect()
|
connect()
|
||||||
|
@ -79,6 +88,7 @@ module NatPMP
|
||||||
end
|
end
|
||||||
|
|
||||||
def connect
|
def connect
|
||||||
|
# @socket.join_group(Socket::IPAddress.new("224.0.0.1", 5351))
|
||||||
@socket.connect(@gateway_ip, 5351)
|
@socket.connect(@gateway_ip, 5351)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -99,6 +109,11 @@ module NatPMP
|
||||||
@socket.receive(msg)
|
@socket.receive(msg)
|
||||||
break
|
break
|
||||||
rescue IO::TimeoutError
|
rescue IO::TimeoutError
|
||||||
|
# If no
|
||||||
|
# NAT-PMP response is received from the gateway after 250 ms, the
|
||||||
|
# client retransmits its request and waits 500 ms. The client SHOULD
|
||||||
|
# repeat this process with the interval between attempts doubling each
|
||||||
|
# time.
|
||||||
@socket.read_timeout = @socket.read_timeout.not_nil!*2
|
@socket.read_timeout = @socket.read_timeout.not_nil!*2
|
||||||
next
|
next
|
||||||
rescue
|
rescue
|
||||||
|
@ -112,6 +127,9 @@ module NatPMP
|
||||||
result_code = decode_msg(UInt16, msg[2..3])
|
result_code = decode_msg(UInt16, msg[2..3])
|
||||||
epoch = decode_msg(UInt32, msg[4..7])
|
epoch = decode_msg(UInt32, msg[4..7])
|
||||||
|
|
||||||
|
# If the result code is non-zero, the value of the External
|
||||||
|
# IPv4 Address field is undefined (MUST be set to zero on transmission,
|
||||||
|
# and MUST be ignored on reception).
|
||||||
if result_code != 0
|
if result_code != 0
|
||||||
ip_address = nil
|
ip_address = nil
|
||||||
else
|
else
|
||||||
|
@ -120,7 +138,6 @@ module NatPMP
|
||||||
return vers, op, result_code, epoch, ip_address
|
return vers, op, result_code, epoch, ip_address
|
||||||
end
|
end
|
||||||
|
|
||||||
# https://datatracker.ietf.org/doc/html/rfc6886#section-3.3
|
|
||||||
def request_mapping(internal_port : UInt16, external_port : UInt16, operation : UInt8, lifetime : UInt32 = 7200)
|
def request_mapping(internal_port : UInt16, external_port : UInt16, operation : UInt8, lifetime : UInt32 = 7200)
|
||||||
request = MappingPacket.new(internal_port, external_port, lifetime, operation).to_slice
|
request = MappingPacket.new(internal_port, external_port, lifetime, operation).to_slice
|
||||||
msg = Bytes.new(16)
|
msg = Bytes.new(16)
|
||||||
|
|
Loading…
Reference in a new issue