Skip to content

Commit b124cb3

Browse files
committed
Handle unassigned blocks. Issue #254
1 parent f273b48 commit b124cb3

File tree

5 files changed

+78
-47
lines changed

5 files changed

+78
-47
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ installation
6767

6868
Run `cd node_modules/geoip-lite && npm run-script updatedb license_key=YOUR_LICENSE_KEY` to update the data files. (Replace `YOUR_LICENSE_KEY` with your license key obtained from [maxmind.com](https://support.maxmind.com/hc/en-us/articles/4407111582235-Generate-a-License-Key))
6969

70-
You can create maxmind account [here](https://www.maxmind.com/en/geolite2/signup)
70+
You can create a maxmind account [here](https://www.maxmind.com/en/geolite2/signup)
7171

7272
**NOTE** that this requires a lot of RAM. It is known to fail on on a Digital Ocean or AWS micro instance.
7373
There are no plans to change this. `geoip-lite` stores all data in RAM in order to be fast.

lib/geoip.js

+25-19
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function lookup4(ip) {
7777
eu:'',
7878
timezone:'',
7979
city: '',
80-
ll: [0, 0]
80+
ll: [null, null]
8181
};
8282

8383
// outside IPv4 range
@@ -105,15 +105,18 @@ function lookup4(ip) {
105105
} else {
106106
locId = buffer.readUInt32BE((line * recordSize) + 8);
107107

108-
geodata.country = locBuffer.toString('utf8', (locId * locRecordSize) + 0, (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
109-
geodata.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
110-
geodata.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
111-
geodata.ll[0] = buffer.readInt32BE((line * recordSize) + 12)/10000;//latitude
112-
geodata.ll[1] = buffer.readInt32BE((line * recordSize) + 16)/10000; //longitude
113-
geodata.area = buffer.readUInt32BE((line * recordSize) + 20); //longitude
114-
geodata.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
115-
geodata.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
116-
geodata.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
108+
// -1>>>0 is a marker for "No Location Info"
109+
if(-1>>>0 > locId) {
110+
geodata.country = locBuffer.toString('utf8', (locId * locRecordSize) + 0, (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
111+
geodata.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
112+
geodata.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
113+
geodata.ll[0] = buffer.readInt32BE((line * recordSize) + 12)/10000;//latitude
114+
geodata.ll[1] = buffer.readInt32BE((line * recordSize) + 16)/10000; //longitude
115+
geodata.area = buffer.readUInt32BE((line * recordSize) + 20); //longitude
116+
geodata.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
117+
geodata.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
118+
geodata.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
119+
}
117120
}
118121

119122
return geodata;
@@ -182,15 +185,18 @@ function lookup6(ip) {
182185
} else {
183186
locId = buffer.readUInt32BE((line * recordSize) + 32);
184187

185-
geodata.country = locBuffer.toString('utf8', (locId * locRecordSize) + 0, (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
186-
geodata.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
187-
geodata.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
188-
geodata.ll[0] = buffer.readInt32BE((line * recordSize) + 36)/10000;//latitude
189-
geodata.ll[1] = buffer.readInt32BE((line * recordSize) + 40)/10000; //longitude
190-
geodata.area = buffer.readUInt32BE((line * recordSize) + 44); //area
191-
geodata.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
192-
geodata.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
193-
geodata.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
188+
// -1>>>0 is a marker for "No Location Info"
189+
if(-1>>>0 > locId) {
190+
geodata.country = locBuffer.toString('utf8', (locId * locRecordSize) + 0, (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
191+
geodata.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
192+
geodata.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
193+
geodata.ll[0] = buffer.readInt32BE((line * recordSize) + 36)/10000;//latitude
194+
geodata.ll[1] = buffer.readInt32BE((line * recordSize) + 40)/10000; //longitude
195+
geodata.area = buffer.readUInt32BE((line * recordSize) + 44); //area
196+
geodata.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
197+
geodata.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
198+
geodata.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
199+
}
194200
}
195201
// We do not currently have detailed region/city info for IPv6, but finally have coords
196202
return geodata;

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name" : "geoip-lite",
3-
"version" : "1.4.7",
3+
"version" : "1.4.8",
44
"description" : "A light weight native JavaScript implementation of GeoIP API from MaxMind",
55
"keywords" : ["geo", "geoip", "ip", "ipv4", "ipv6", "geolookup", "maxmind", "geolite"],
66
"homepage" : "https://github.com/geoip-lite/node-geoip",

scripts/updatedb.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ if (typeof geodatadir !== 'undefined') {
4646
}
4747
var tmpPath = process.env.GEOTMPDIR ? process.env.GEOTMPDIR : path.resolve(__dirname, '..', 'tmp');
4848
var countryLookup = {};
49-
var cityLookup = {};
49+
var cityLookup = {NaN: -1};
5050
var databases = [
5151
{
5252
type: 'country',
@@ -538,7 +538,7 @@ function processCityDataNames(src, dest, cb) {
538538
var sz = 88;
539539
var fields = CSVtoArray(line);
540540
if (!fields) {
541-
//lot's of cities contain ` or ' in the name and can't be parsed correctly with current method
541+
//lots of cities contain ` or ' in the name and can't be parsed correctly with current method
542542
console.log("weird line: %s::", line);
543543
return;
544544
}

test/tests.js

+49-24
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ module.exports = {
2626
var actual = geoip.lookup(ip);
2727

2828
test.notStrictEqual(actual.range, undefined, 'should contain IPv4 range');
29-
29+
3030
test.strictEqual(actual.country, 'US', "should match country");
31-
31+
3232
test.strictEqual(actual.region, 'NY', "should match region");
33-
33+
3434
test.strictEqual(actual.eu, '0', "should match eu");
35-
35+
3636
test.strictEqual(actual.timezone, 'America/New_York', "should match timezone");
37-
37+
3838
test.strictEqual(actual.city, 'New York', "should match city");
39-
39+
4040
test.ok(actual.ll, 'should contain coordinates');
41-
41+
4242
test.strictEqual(actual.metro, 501, "should match metro");
43-
43+
4444
test.strictEqual(actual.area, 1, "should match area");
4545

4646
test.done();
@@ -54,21 +54,21 @@ module.exports = {
5454
var actual = geoip.lookup(ipv6);
5555

5656
test.notStrictEqual(actual.range, undefined, 'should contain IPv6 range');
57-
57+
5858
test.strictEqual(actual.country, 'NL', "should match country");
59-
59+
6060
test.strictEqual(actual.region, 'NH', "should match region");
61-
61+
6262
test.strictEqual(actual.eu, '1', "should match eu");
63-
63+
6464
test.strictEqual(actual.timezone, 'Europe/Amsterdam', "should match timezone");
65-
65+
6666
test.strictEqual(actual.city, 'Amsterdam', "should match city");
67-
67+
6868
test.ok(actual.ll, 'should contain coordinates');
69-
69+
7070
test.strictEqual(actual.metro, 0, "should match metro");
71-
71+
7272
test.strictEqual(actual.area, 5, "should match area");
7373

7474
test.done();
@@ -115,22 +115,22 @@ module.exports = {
115115
//get original data
116116
var before4 = geoip.lookup("75.82.117.180");
117117
test.notEqual(before4, null);
118-
118+
119119
var before6 = geoip.lookup("::ffff:173.185.182.82");
120120
test.notEqual(before6, null);
121-
121+
122122
//clear data;
123123
geoip.clear();
124-
124+
125125
//make sure data is cleared
126126
var none4 = geoip.lookup("75.82.117.180");
127127
test.equal(none4, null);
128128
var none6 = geoip.lookup("::ffff:173.185.182.82");
129129
test.equal(none6, null);
130-
130+
131131
//reload data synchronized
132132
geoip.reloadDataSync();
133-
133+
134134
//make sure we have value from before
135135
var after4 = geoip.lookup("75.82.117.180");
136136
test.deepEqual(before4, after4);
@@ -148,16 +148,16 @@ module.exports = {
148148
test.notEqual(before4, null);
149149
var before6 = geoip.lookup("::ffff:173.185.182.82");
150150
test.notEqual(before6, null);
151-
151+
152152
//clear data;
153153
geoip.clear();
154-
154+
155155
//make sure data is cleared
156156
var none4 = geoip.lookup("75.82.117.180");
157157
test.equal(none4, null);
158158
var none6 = geoip.lookup("::ffff:173.185.182.82");
159159
test.equal(none6, null);
160-
160+
161161
//reload data asynchronously
162162
geoip.reloadData(function(){
163163
//make sure we have value from before
@@ -168,5 +168,30 @@ module.exports = {
168168

169169
test.done();
170170
});
171+
},
172+
173+
testUnassigned: function (test) {
174+
test.expect(8);
175+
176+
var ip = '1.1.1.1';
177+
178+
var actual = geoip.lookup(ip);
179+
180+
test.notStrictEqual(actual.range, undefined, 'should contain IPv4 range');
181+
182+
test.strictEqual(actual.country, '', "should match empty country");
183+
184+
test.strictEqual(actual.region, '', "should match empty region");
185+
186+
test.strictEqual(actual.eu, '', "should match empty eu");
187+
188+
test.strictEqual(actual.timezone, '', "should match empty timezone");
189+
190+
test.strictEqual(actual.city, '', "should match empty city");
191+
192+
test.strictEqual(actual.ll[0], null, 'should contain empty coordinates');
193+
test.strictEqual(actual.ll[1], null, 'should contain empty coordinates');
194+
195+
test.done();
171196
}
172197
};

0 commit comments

Comments
 (0)