Class: LogStash::Filters::Forwarded

Inherits:
Base
  • Object
show all
Defined in:
lib/logstash/filters/forwarded.rb

Overview

The forwarded filter extracts the client ip from a list of ip adresses. The client ip might be at any position in the list, since not every x-forwarded-for header comes in the correct ordering. It adds two new fields to the event:

- forwarded_client_ip : string
- forwarded_proxy_list : string[]

Instance Method Summary collapse

Instance Method Details

#analyse(ip) ⇒ Object

def filter



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/logstash/filters/forwarded.rb', line 66

def analyse(ip)
  return nil, nil if ip.nil?
    # convert the x-forwarded-for string into an array of its comma separated value, if it isn't already.
    ip_list = ip.is_a?(Array) ? ip : ip.downcase.split(",")

    # remove some well-known invalid values
    ip_list = ip_list.map { |x| x.strip }.reject { |x| ["-", "unknown"].include? x}

    # the IpAddr library cannot handle ips with port numbers
    ip_list = ip_list.map { |x| remove_port_number(x) }

    # get the first public ip in the list
    client_ip = get_client_ip(ip_list)

    # remove the public / client ip from the list and use the remainder as the list of proxies involved.
    proxies = ip_list.nil? ? nil : ip_list - [client_ip]

    return client_ip, proxies
end

#filter(event) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/logstash/filters/forwarded.rb', line 46

def filter(event)
  return unless filter?(event)

  begin
    forwarded = event.get(@source)

    return unless forwarded and !forwarded.empty?

    client_ip, proxies = analyse(forwarded)

    event.set(@target_client_ip, client_ip) if client_ip
    event.set(@target_proxy_list, proxies) if proxies
    filter_matched(event)

  rescue Exception => e
    @logger.debug("Unknown error while looking up GeoIP data", :exception => e, :field => @source, :event => event)
    # raise e
  end # begin
end

#get_client_ip(ip_array) ⇒ Object

def analyse



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/logstash/filters/forwarded.rb', line 86

def get_client_ip(ip_array)
    ip_array.each do | ip |
      begin
        next if !IPAddress.valid? ip

        ipo = IPAddr.new(ip)
        is_private = ipo.ipv6? ? is_private_ipv6(ip) : is_private_ipv4(ipo)
        return ip if !is_private
      rescue => e
        # not a valid ip, moving on.
        # @logger.debug("get_client_ip() failed", :exception => e, :field => @source, :ip_array => ip_array)
        next
      end
    end # each
    nil
end

#is_private_ipv4(ipo) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/logstash/filters/forwarded.rb', line 113

def is_private_ipv4(ipo)
  begin
    @private_ipv4_ranges.each do | ip_range |
      return true if ip_range.include?(ipo)
    end # each
    false
  rescue => e
    @logger.debug("Couldn't check if ip is private.", :input_data => ip, :exception => e)
  end # begin
end

#is_private_ipv6(ip) ⇒ Object



108
109
110
# File 'lib/logstash/filters/forwarded.rb', line 108

def is_private_ipv6(ip)
  ip.start_with?("fd") || ip.start_with?("fc")
end

#registerObject



33
34
35
36
37
38
39
40
41
42
43
# File 'lib/logstash/filters/forwarded.rb', line 33

def register
  @private_ipv4_ranges = @private_ipv4_prefixes.collect do | adress |
    begin
      IPAddr.new(adress)
    rescue ArgumentError => e
      @logger.error("Register: invalid IP network, skipping", :adress => adress, :exception => e)
      raise e
     end
  end
  @private_ipv4_ranges.compact!
end

#remove_port_number(ip) ⇒ Object

get_client_ip



103
104
105
106
# File 'lib/logstash/filters/forwarded.rb', line 103

def remove_port_number(ip)
  tokens = ip.split(":")
  if tokens.size <=2 then tokens[0] else ip end
end