apache-log-geo 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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