forked from urbanadventurer/urlcrazy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
country.rb
110 lines (97 loc) · 3.15 KB
/
country.rb
1
2
3
4
5
6
7
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
40
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
class Countrylookup
# This is borrowed from WhatWeb
# Lookup code developed by Matthias Wachter for rubyquiz.com and used with permission.
# Local IPv4 addresses are represented as ZZ according to an ISO convention.
# How to Update Database
# ----------------------
# rm plugins/country-ips.dat plugins/IpToCountry.csv
# wget software77.net/geo-ip/?DL=1 -O plugins/IpToCountry.csv.gz
# gzip -d plugins/IpToCountry.csv.gz
def Countrylookup.startup
# ok, set up @rfile. open once.
folder=File.expand_path(File.dirname(__FILE__))
country_db = folder + "/country-ips.dat"
if File.exists?(country_db)
@rfile=File.open(country_db,"rb")
else
if File.exists?(folder + "/IpToCountry.csv")
# pack that file & do it once
last_start=nil
last_end=nil
last_country=nil
File.open(folder + "/country-ips.dat","wb") do |wfile|
IO.foreach(folder + "/IpToCountry.csv") do |line|
next if line[0..0] =="#"
next if !(line =~ /^"/ )
s,e,d1,d2,co=line.delete!("\"").split(",")
s,e = s.to_i,e.to_i
if !last_start
# initialize with first entry
last_start,last_end,last_country = s,e,co
else
if s==last_end+1 and co==last_country
# squeeze if successive ranges have zero gap
last_end=e
else
# append last entry, remember new one
wfile << [last_start,last_end,last_country].pack("NNa2")
last_start,last_end,last_country = s,e,co
end
end
end
# print last entry
if last_start
wfile << [last_start,last_end,last_country].pack("NNa2")
end
end
# open the DB now
@rfile=File.open(country_db,"rb")
else
raise "Aborting: Cannot find country database."
end
end
f = folder + "/country-codes.txt"
@ccnames={};
File.open(f,"r:UTF-8").readlines.each do |line|
x=line.split(",");
@ccnames[x[1]] = x[0]
end
end
def Countrylookup.ip2cc(ip)
found=[]
$semaphore_countrylookup.synchronize do
if @rfile and ip and ip =~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/
@rfile.seek(0,IO::SEEK_END)
[email protected]/10-1
# build a 4-char string representation of IP address
# in network byte order so it can be a string compare below
ipstr= ip.split(".").map {|x| x.to_i.chr}.join
# low/high water marks initialized
low,high=0,record_max
while true
mid=(low+high)/2 # binary search median
@rfile.seek(10*mid) # one record is 10 byte, seek to position
[email protected](8) # for range matching, we need only 8 bytes
# at comparison, values are big endian, i.e. packed("N")
if ipstr>=str[0,4] # is this IP not below the current range?
if ipstr<=str[4,4] # is this IP not above the current range?
#puts # a perfect match, voila!
found = [cc,@ccnames[cc]]
break
else
low=mid+1 # binary search: raise lower limit
end
else
high=mid-1 # binary search: reduce upper limit
end
if low>high # no entries left? nothing found
#m << {:string=>"No country"}
break
end
end
end
end
found
end
end