apache-log-geo 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -1
  3. data/apache-log-geo +10 -10
  4. data/lib.rb +25 -0
  5. data/mmdb-lookup +16 -11
  6. metadata +6 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88358db0f03c32a5141201af91a3fa617f123b00c0fad7a8e063a4e51a1fe75e
4
- data.tar.gz: 37906a57323328d07d516d3b7b6bb5cc71ffb200949158206f952708e1df0cb0
3
+ metadata.gz: d5f696d02b3eea816384b389250916a180e3b219ad52ecc01ad8fcc42ce664de
4
+ data.tar.gz: 3b2c584d7cde234fd15918eca2826d4d674806d43bf8ea244b22022916b55dab
5
5
  SHA512:
6
- metadata.gz: edba9d9da0d8e342b84403df8d6459f449aac6c65cb5d69b59f696a69562aea26c4a3a7febae2928d2852721301bb0b9564d38a38fa21fca6c1fe062e5c39234
7
- data.tar.gz: dde46e90f32f32fc69b7292e12db7687f2319d3b6a308f088996f9fab24b91a30d4c355a75e38448e3eeff5fd7b5c35954a3acf7423b34230b55c3ced543698b
6
+ metadata.gz: 57bb8e647db969849aa7e341def0459ec28c0ccc7806e6cca6a5d6c63beb976bdd097621f6d4f66a8a65b7b780ab5a76653cf190fd83ceb99b3a1be2f96e81e5
7
+ data.tar.gz: d3341602fb3df5c81af39f1dfcbdbf83576472bdc4bcc1208538db93497e6153f18c2afe50b73787524aa524d428e0a3c2e1310dc1b248e28b48fed5fd3109ff
data/README.md CHANGED
@@ -17,6 +17,12 @@ key & install geoipupdate to fetch the db file.
17
17
 
18
18
  gem install apache-log-geo
19
19
 
20
+ It uses a C extension [geoip2_c][], instead of the official maxmind-db
21
+ gem, for in my local tests, the latter (in conjunction with the Ruby
22
+ IO) is 9 (nine) times slower!
23
+
24
+ [geoip2_c]: https://github.com/fluent-plugins-nursery/geoip2_c
25
+
20
26
  ## Usage
21
27
 
22
28
  The pkg contains 2 CLI utils only. There's no reusable library code.
@@ -33,6 +39,7 @@ Usage: apache-log-geo [-d GeoLite2-City.mmdb] [-v] [--key val ...]
33
39
  --city regexp
34
40
  --country regexp
35
41
  --cc str 2 letter country code
42
+ --eu is an EU member?
36
43
  --continent regexp
37
44
  --postcode regexp
38
45
  --sub regexp subdivisions
@@ -96,7 +103,7 @@ Kyiv City
96
103
  Replicate `apache-log-geo` util--print only the requests from the Irish
97
104
  (the example requires `npm -g json`):
98
105
 
99
- $ awk '{print $1}' test/access.log | ./mmdb-lookup | json -c 'this.country_code == "IE"' -a ip | grep -h -f - test/access.log
106
+ $ cat test/access.log | ./mmdb-lookup | json -c 'this.country_code == "IE"' -a ip | grep -h -f - test/access.log
100
107
 
101
108
  ## Exit status
102
109
 
data/apache-log-geo CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'optparse'
4
- require 'mmdb'
5
4
  require_relative 'lib'
6
5
  include ApacheLogGeo
7
6
 
8
- # exact match: country_code, postcode
9
- # regexp: continent, country, subdivisions, city
10
- #
11
7
  # conditions are anded. no conditions == true
12
8
  def match_by_geo info, query
13
9
  query.each do |k,v|
10
+ if k == :eu # --eu is a boolean
11
+ return false unless info[k]
12
+ end
13
+
14
14
  if k == :subdivisions # it's an array, one match of its elements is enough
15
15
  return false unless (info[k] || []).any? {|val| val.to_s =~ /#{v}/i }
16
16
  end
@@ -39,25 +39,25 @@ OptionParser.new do |o|
39
39
  end
40
40
  opt[:query][:country_code] = v
41
41
  }
42
+ o.on("--eu", "is an EU member?") { opt[:query][:eu] = true }
42
43
  o.on("--continent regexp") { |v| opt[:query][:continent] = v }
43
44
  o.on("--postcode regexp") { |v| opt[:query][:postcode] = v }
44
45
  o.on("--sub regexp", "subdivisions") { |v| opt[:query][:subdivisions] = v }
45
46
  end.parse!
46
47
 
47
48
  begin
48
- geo = MaxMindDB.new opt[:db]
49
+ geo = GeoDB.new opt[:db]
49
50
  rescue
50
- errx 2, "failed to open #{opt[:db]}"
51
+ errx 2, $!
51
52
  end
52
53
 
53
54
  found_anything = false
54
55
  $stdin.each_line do |line|
55
56
  next if line =~ /^\s*$/
56
57
  ip = line.split[0]
57
- begin
58
- info = geo.lookup ip
59
- rescue
60
- warnx "no data, filtering the entry out: `${ip[0..15]}`"
58
+ info = geo.get ip
59
+ unless info
60
+ warnx "line #{$stdin.lineno}: no data, filtering out: #{ip[0..15]}"
61
61
  next
62
62
  end
63
63
 
data/lib.rb CHANGED
@@ -273,3 +273,28 @@ module ApacheLogGeo
273
273
  "ZW" => "Zimbabwe"
274
274
  }
275
275
  end
276
+
277
+ require 'geoip2'
278
+
279
+ class ApacheLogGeo::GeoDB
280
+ def initialize path
281
+ @db = GeoIP2::Database.new path
282
+ end
283
+
284
+ def get ip
285
+ r = @db.lookup ip rescue nil
286
+ return nil unless r
287
+
288
+ {
289
+ city: r.dig('city', 'names', 'en'),
290
+ continent: r.dig('continent', 'names', 'en'),
291
+ country: r.dig('country', 'names', 'en'),
292
+ country_code: r.dig('country', 'iso_code'),
293
+ eu: r.dig('country', 'is_in_european_union'),
294
+ latitude: r.dig('location', 'latitude'),
295
+ longitude: r.dig('location', 'longitude'),
296
+ postcode: r.dig('postal', 'code'),
297
+ subdivisions: r.dig('subdivisions')&.map {|v| v&.dig('names', 'en') }&.compact
298
+ }
299
+ end
300
+ end
data/mmdb-lookup CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'optparse'
4
- require 'mmdb'
5
4
  require_relative 'lib'
6
5
  include ApacheLogGeo
7
6
 
@@ -17,7 +16,7 @@ class FMT
17
16
  ip = @input.to_enum.next.split.first
18
17
  r = ["ip=#{ip.shellescape}"]
19
18
 
20
- info = @geo.lookup ip rescue nil
19
+ info = @geo.get ip
21
20
  if !info
22
21
  r << "error=#{@errors += 1}"
23
22
  else
@@ -30,13 +29,19 @@ class FMT
30
29
 
31
30
  def json
32
31
  require 'json'
33
- @input.map do |list|
34
- list.split.map do |ip|
35
- r = {ip: ip}
36
- info = @geo.lookup ip rescue nil
37
- info ? r.merge(info) : r.merge({error: @errors += 1})
38
- end
39
- end.flatten.to_json
32
+ trans = -> (ip) do
33
+ r = {ip: ip}
34
+ info = @geo.get ip
35
+ info ? r.merge(info) : r.merge({error: @errors += 1})
36
+ end
37
+
38
+ if @input.is_a?(IO) # stdin, in which we expect an apache log
39
+ @input.map { |line| trans.call line.split[0] }.to_json
40
+ else # argv
41
+ @input.map do |list|
42
+ list.split.map { |ip| trans.call ip }
43
+ end.flatten.to_json
44
+ end
40
45
  end
41
46
  end
42
47
 
@@ -53,9 +58,9 @@ OptionParser.new do |o|
53
58
  end.parse!
54
59
 
55
60
  begin
56
- geo = MaxMindDB.new opt[:db]
61
+ geo = GeoDB.new opt[:db]
57
62
  rescue
58
- errx 2, "failed to open #{opt[:db]}"
63
+ errx 2, $!
59
64
  end
60
65
 
61
66
  fmt = FMT.new (ARGV.size > 0 ? ARGV : $stdin), geo
metadata CHANGED
@@ -1,30 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apache-log-geo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Gromnitsky
8
8
  autorequire:
9
9
  bindir: "."
10
10
  cert_chain: []
11
- date: 2020-03-08 00:00:00.000000000 Z
11
+ date: 2020-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: mmdb
14
+ name: geoip2_c
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.2
19
+ version: 0.3.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.2
26
+ version: 0.3.3
27
27
  description: |
28
+ An offline GeoIP CLI filter for Apache (common, combined) logs.
28
29
  It's like grep but with a knowledge about what data an ip
29
30
  holds. Requires MaxMind's GeoLite2 DB (GeoLite2-City.mmdb) installed.
30
31
  email: alexander.gromnitsky@gmail.com