Class: StunClient::RFC3489LifetimeDiscovery

Inherits:
Object
  • Object
show all
Defined in:
lib/stun-client/rfc3489/discovery/lifetime.rb

Overview

Helper to determine the Binding Lifetime of a NAT.

Note: This helper has not been tested yet. The reason is that I have not found a STUN server that supports the Response Address Attribute.

Instance Method Summary collapse

Constructor Details

#initialize(host = nil, port = nil, protocol = :IPv4) ⇒ RFC3489LifetimeDiscovery

Creates a new object for NAT lifetime discovery.

Parameters:

  • host (String) (defaults to: nil)

    The host of the STUN server to be used for NAT discovery. By default, the default server of the STUN client is used.

  • port (Integer) (defaults to: nil)

    The port of the STUN server.

  • protocol (Symbol) (defaults to: :IPv4)

    Defines whether the STUN server should be reached via IPv4 or IPv6. Accordingly like a NATv4 or NATv6 detected. Possible values are ‘:IPv4` or `:IPv6`.

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/stun-client/rfc3489/discovery/lifetime.rb', line 22

def initialize host = nil, port = nil, protocol = :IPv4
  raise ArgumentError, 'Host must be a string' if host && (! host.is_a? String)
  raise ArgumentError, 'Port must be a integer' if port && (! host.is_a? Integer)

  case protocol
  when :IPv6
    @inet = Socket::AF_INET6
    @addr = '::'
  when :IPv4
    @inet = Socket::AF_INET
    @addr = '0.0.0.0'
  else
    raise ArgumentError, 'Unknown protocol'
  end

  @host = host
  @port = port
end

Instance Method Details

#alive_in_time?(time) ⇒ TrueClass, FalseClass

Checks if the NAT Binding Lifetime is less than the specified time.

For this, a STUN server is contacted to determine its own host and port. Afterwards it is waited accordingly. Then the STUN server is contacted again from another socket and instructed to send a STUN binding response to the previous socket. If the response arrives, the binding lifetime has not been exceeded. If no response is received, the binding lifetime is exceeded.

Parameters:

  • time (Integer)

Returns:

  • (TrueClass, FalseClass)

    Returns false if the binding lifetime has been exceeded, otherwise true.

Raises:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/stun-client/rfc3489/discovery/lifetime.rb', line 85

def alive_in_time? time
  raise 'The waiting time must be an integer.' if ! time.is_a? Integer

  socket_a = create_socket
  resp = do_query socket_a
  raise TimeoutError, 'UDP blocked.' if ! resp

  host = resp[:host]
  port = resp[:port].to_i

  # rubocop:disable Style/NumericLiterals
  raise 'The server has returned an invalid port.' if port.zero? || port > 65535
  # rubocop:enable Style/NumericLiterals

  sleep time

  socket_b = create_socket
  resp = do_query socket_b, response_ip: host, response_port: port

  return ( resp ? true : false )
end

#detect_binding_lifetime(max = 1200, min = 0) ⇒ Integer

Measures the Binding Lifetime of a NAT.

Parameters:

  • max (Integer) (defaults to: 1200)

    Specifies the maximum lifetime after which the measurement is to be aborted.

  • min (Integer) (defaults to: 0)

    Specifies the minimum lifetime. If the lifetime is less than this, the program is aborted. It is recommended to leave this at zero.

Returns:

  • (Integer)

    Specifies the NAT Binding Lifetime. If it is greater than the allowed maximum, the maximum itself is returned. If it is less than the allowed minimum, the minimum itself is returned.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/stun-client/rfc3489/discovery/lifetime.rb', line 57

def detect_binding_lifetime max = 1200, min = 0
  raise 'STUN server does not support response address.' if ! alive_in_time?(0)

  while min < max
    mid = (min + max) / 2

    if alive_in_time? mid
      min = mid + 1
    else
      max = mid - 1
    end
  end

  return max
end