class Object

Public Instance Methods

get_client_address(env) click to toggle source
# File lib/moesif_rack/client_ip.rb, line 48
def get_client_address(env)
    begin
        # Standard headers used by Amazon EC2, Heroku, and others.
        if env.key?('HTTP_X_CLIENT_IP')
            if is_ip?(env['HTTP_X_CLIENT_IP'])
                return env['HTTP_X_CLIENT_IP']
            end
        end

        # 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'])
            if is_ip?(xForwardedFor)
                return xForwardedFor
            end
        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.
        if env.key?('HTTP_CF_CONNECTING_IP')
            if is_ip?(env['HTTP_CF_CONNECTING_IP'])
                return env['HTTP_CF_CONNECTING_IP']
            end
        end

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

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

        # (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')
            if is_ip?(env['HTTP_X_CLUSTER_CLIENT_IP'])
                return env['HTTP_X_CLUSTER_CLIENT_IP']
            end
        end

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

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

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

        return env['REMOTE_ADDR']
    rescue 
        return env['REMOTE_ADDR']
    end
end
get_client_ip_from_x_forwarded_for(value) click to toggle source
# File lib/moesif_rack/client_ip.rb, line 9
def get_client_ip_from_x_forwarded_for(value)
    begin
        value = value.encode('utf-8')

        if value.to_s.empty?
            return nil
        end

        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(':')
                    if splitted.length == 2 
                        forwardedIps << splitted.first
                    end
               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/)
            return forwardedIps.find {|e| is_ip?(e) }
        end
    rescue
        return value.encode('utf-8')
    end
end
is_ip?(value) click to toggle source
# File lib/moesif_rack/client_ip.rb, line 2
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