Top Level Namespace

Defined Under Namespace

Modules: MoesifRack, RULE_TYPES Classes: AppConfig, CompanyHelper, GovernanceRules, MoesifHelpers, RegexConfigHelper, UserHelper

Instance Method Summary collapse

Instance Method Details

#get_client_address(env) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/moesif_rack/client_ip.rb', line 41

def get_client_address(env)
  # Standard headers used by Amazon EC2, Heroku, and others.
  return env['HTTP_X_CLIENT_IP'] if env.key?('HTTP_X_CLIENT_IP') && is_ip?(env['HTTP_X_CLIENT_IP'])

  # Load-balancers (AWS ELB) or proxies.
  if env.key?('HTTP_X_FORWARDED_FOR')
    xForwardedFor = get_client_ip_from_x_forwarded_for(env['HTTP_X_FORWARDED_FOR'])
    return xForwardedFor if is_ip?(xForwardedFor)
  end

  # Cloudflare.
  # @see https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
  # CF-Connecting-IP - applied to every request to the origin.
  return env['HTTP_CF_CONNECTING_IP'] if env.key?('HTTP_CF_CONNECTING_IP') && is_ip?(env['HTTP_CF_CONNECTING_IP'])

  # Akamai and Cloudflare: True-Client-IP.
  return env['HTTP_TRUE_CLIENT_IP'] if env.key?('HTTP_TRUE_CLIENT_IP') && is_ip?(env['HTTP_TRUE_CLIENT_IP'])

  # Default nginx proxy/fcgi; alternative to x-forwarded-for, used by some proxies.
  return env['HTTP_X_REAL_IP'] if env.key?('HTTP_X_REAL_IP') && is_ip?(env['HTTP_X_REAL_IP'])

  # (Rackspace LB and Riverbed's Stingray)
  # http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
  # https://splash.riverbed.com/docs/DOC-1926
  if env.key?('HTTP_X_CLUSTER_CLIENT_IP') && is_ip?(env['HTTP_X_CLUSTER_CLIENT_IP'])
    return env['HTTP_X_CLUSTER_CLIENT_IP']
  end

  return env['HTTP_X_FORWARDED'] if env.key?('HTTP_X_FORWARDED') && is_ip?(env['HTTP_X_FORWARDED'])

  return env['HTTP_FORWARDED_FOR'] if env.key?('HTTP_FORWARDED_FOR') && is_ip?(env['HTTP_FORWARDED_FOR'])

  return env['HTTP_FORWARDED'] if env.key?('HTTP_FORWARDED') && is_ip?(env['HTTP_FORWARDED'])

  env['REMOTE_ADDR']
rescue StandardError
  env['REMOTE_ADDR']
end

#get_client_ip_from_x_forwarded_for(value) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/moesif_rack/client_ip.rb', line 8

def get_client_ip_from_x_forwarded_for(value)
  value = value.encode('utf-8')

  return nil if value.to_s.empty?

  if !value.instance_of?(String)
    puts('Expected a string, got - ' + value.class.to_s)
  else
    # x-forwarded-for may return multiple IP addresses in the format:
    # "client IP, proxy 1 IP, proxy 2 IP"
    # Therefore, the right-most IP address is the IP address of the most recent proxy
    # and the left-most IP address is the IP address of the originating client.
    # source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
    # Azure Web App's also adds a port for some reason, so we'll only use the first part (the IP)
    forwardedIps = []

    value.gsub(/\s+/, '').split(',').each do |e|
      if e.include?(':')
        splitted = e.split(':')
        forwardedIps << splitted.first if splitted.length == 2
      end
      forwardedIps << e
    end

    # Sometimes IP addresses in this header can be 'unknown' (http://stackoverflow.com/a/11285650).
    # Therefore taking the left-most IP address that is not unknown
    # A Squid configuration directive can also set the value to "unknown" (http://www.squid-cache.org/Doc/config/forwarded_for/)
    forwardedIps.find { |e| is_ip?(e) }
  end
rescue StandardError
  value.encode('utf-8')
end

#is_ip?(value) ⇒ Boolean

Returns:

  • (Boolean)


1
2
3
4
5
6
# File 'lib/moesif_rack/client_ip.rb', line 1

def is_ip?(value)
  ipv4 = /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
  ipv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
  # We use !! to convert the return value to a boolean
  !!(value =~ ipv4 or value =~ ipv6)
end