Skip to content

Commit c0c3285

Browse files
committed
Reduced file I/O
1 parent 94e9f9f commit c0c3285

File tree

3 files changed

+113
-53
lines changed

3 files changed

+113
-53
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ip2proxy-nodejs",
3-
"version": "4.1.0",
3+
"version": "4.2.0",
44
"description": "IP2Proxy proxy detection component",
55
"keywords": [
66
"vpn-detection",

src/ip2proxy.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ export class IP2Proxy {
22
readRow(readBytes: any, position: any): any;
33
readBin(readBytes: any, position: any, readType: any, isBigInt: any): any;
44
read8(position: any): any;
5+
read8Row(position: any, buffer: any): any;
56
read32(position: any, isBigInt: any): any;
67
read32Row(position: any, buffer: any): any;
8+
read128Row(position: any, buffer: any): any;
9+
read32Or128Row(position: any, buffer: any, len: any): any;
710
read32Or128(position: any, ipType: any): any;
811
read128(position: any): any;
912
readStr(position: any): any;
@@ -72,4 +75,4 @@ export class IP2ProxyWebService {
7275
lookup(myIP: any, callback: any): void;
7376
getCredit(callback: any): void;
7477
#private;
75-
}
78+
}

src/ip2proxy.js

Lines changed: 108 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var bigInt = require("big-integer");
44
var https = require("https");
55

66
// For BIN queries
7-
const VERSION = "4.1.0";
7+
const VERSION = "4.2.0";
88
const MAX_INDEX = 65536;
99
const COUNTRY_POSITION = [0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3];
1010
const REGION_POSITION = [0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4];
@@ -105,6 +105,8 @@ class IP2Proxy {
105105
baseAddress: 0,
106106
dbCountIPV6: 0,
107107
baseAddressIPV6: 0,
108+
indexed: 0,
109+
indexedIPV6: 0,
108110
indexBaseAddress: 0,
109111
indexBaseAddressIPV6: 0,
110112
productCode: 0,
@@ -168,6 +170,11 @@ class IP2Proxy {
168170
return this.readBin(readBytes, position - 1, "int8");
169171
}
170172

173+
// Read 8 bits integer in the buffer
174+
read8Row(position, buffer) {
175+
return buffer.readUInt8(position);
176+
}
177+
171178
// Read 32 bits integer in the database
172179
read32(position, isBigInt) {
173180
let readBytes = 4;
@@ -179,6 +186,29 @@ class IP2Proxy {
179186
return buffer.readUInt32LE(position);
180187
}
181188

189+
// Read 128 bits integer in the buffer
190+
read128Row(position, buffer) {
191+
let myBig = bigInt(); // zero
192+
let bitShift = 8;
193+
for (let x = 0; x < 16; x++) {
194+
let pos = position + x;
195+
myBig = myBig.add(
196+
bigInt(this.read8Row(pos, buffer)).shiftLeft(bitShift * x)
197+
);
198+
}
199+
return myBig;
200+
}
201+
202+
read32Or128Row(position, buffer, len) {
203+
if (len == 4) {
204+
return this.read32Row(position, buffer);
205+
} else if (len == 16) {
206+
return this.read128Row(position, buffer);
207+
} else {
208+
return 0;
209+
}
210+
}
211+
182212
read32Or128(position, ipType) {
183213
if (ipType == 4) {
184214
return this.read32(position, true);
@@ -197,12 +227,10 @@ class IP2Proxy {
197227

198228
// Read strings in the database
199229
readStr(position) {
200-
let readBytes = 1;
201-
return this.readBin(
202-
this.readBin(readBytes, position, "int8"),
203-
position + 1,
204-
"str"
205-
);
230+
let readBytes = 256; // max size of string field + 1 byte for the length
231+
let row = this.readRow(readBytes, position + 1);
232+
let len = this.read8Row(0, row);
233+
return row.toString("utf8", 1, len + 1);
206234
}
207235

208236
// Read metadata and indexes
@@ -213,21 +241,24 @@ class IP2Proxy {
213241
if (this.#binFile && this.#binFile != "") {
214242
this.#fd = fs.openSync(this.#binFile, "r");
215243

216-
this.#myDB.dbType = this.read8(1);
217-
this.#myDB.dbColumn = this.read8(2);
218-
this.#myDB.dbYear = this.read8(3);
219-
this.#myDB.dbMonth = this.read8(4);
220-
this.#myDB.dbDay = this.read8(5);
221-
this.#myDB.dbCount = this.read32(6);
222-
this.#myDB.baseAddress = this.read32(10);
223-
this.#myDB.dbCountIPV6 = this.read32(14);
224-
this.#myDB.baseAddressIPV6 = this.read32(18);
225-
this.#myDB.indexBaseAddress = this.read32(22);
226-
this.#myDB.indexBaseAddressIPV6 = this.read32(26);
227-
this.#myDB.productCode = this.read8(30);
244+
let len = 64; // 64-byte header
245+
let row = this.readRow(len, 1);
246+
247+
this.#myDB.dbType = this.read8Row(0, row);
248+
this.#myDB.dbColumn = this.read8Row(1, row);
249+
this.#myDB.dbYear = this.read8Row(2, row);
250+
this.#myDB.dbMonth = this.read8Row(3, row);
251+
this.#myDB.dbDay = this.read8Row(4, row);
252+
this.#myDB.dbCount = this.read32Row(5, row);
253+
this.#myDB.baseAddress = this.read32Row(9, row);
254+
this.#myDB.dbCountIPV6 = this.read32Row(13, row);
255+
this.#myDB.baseAddressIPV6 = this.read32Row(17, row);
256+
this.#myDB.indexBaseAddress = this.read32Row(21, row);
257+
this.#myDB.indexBaseAddressIPV6 = this.read32Row(25, row);
258+
this.#myDB.productCode = this.read8Row(29, row);
228259
// below 2 fields just read for now, not being used yet
229-
this.#myDB.productType = this.read8(31);
230-
this.#myDB.fileSize = this.read32(32);
260+
this.#myDB.productType = this.read8Row(30, row);
261+
this.#myDB.fileSize = this.read32Row(31, row);
231262

232263
// check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
233264
if (
@@ -238,6 +269,14 @@ class IP2Proxy {
238269
throw new Error(MSG_INVALID_BIN);
239270
}
240271

272+
if (this.#myDB.indexBaseAddress > 0) {
273+
this.#myDB.indexed = 1;
274+
}
275+
276+
if (this.#myDB.dbCountIPV6 > 0 && this.#myDB.indexBaseAddressIPV6 > 0) {
277+
this.#myDB.indexedIPV6 = 1;
278+
}
279+
241280
this.#ipV4ColumnSize = this.#myDB.dbColumn << 2; // 4 bytes each column
242281
this.#ipV6ColumnSize = 16 + ((this.#myDB.dbColumn - 1) << 2); // 4 bytes each column, except IPFrom column which is 16 bytes
243282

@@ -285,22 +324,32 @@ class IP2Proxy {
285324
this.#threatEnabled = THREAT_POSITION[dbt] != 0 ? 1 : 0;
286325
this.#providerEnabled = PROVIDER_POSITION[dbt] != 0 ? 1 : 0;
287326

288-
let pointer = this.#myDB.indexBaseAddress;
327+
if (this.#myDB.indexed == 1) {
328+
len = MAX_INDEX;
329+
if (this.#myDB.indexedIPV6 == 1) {
330+
len += MAX_INDEX;
331+
}
332+
len *= 8; // 4 bytes for both From/To
289333

290-
for (let x = 0; x < MAX_INDEX; x++) {
291-
this.#indexArrayIPV4[x] = Array(2);
292-
this.#indexArrayIPV4[x][0] = this.read32(pointer);
293-
this.#indexArrayIPV4[x][1] = this.read32(pointer + 4);
294-
pointer += 8;
295-
}
334+
row = this.readRow(len, this.#myDB.indexBaseAddress);
335+
336+
let pointer = 0;
296337

297-
if (this.#myDB.indexBaseAddressIPV6 > 0) {
298338
for (let x = 0; x < MAX_INDEX; x++) {
299-
this.#indexArrayIPV6[x] = Array(2);
300-
this.#indexArrayIPV6[x][0] = this.read32(pointer);
301-
this.#indexArrayIPV6[x][1] = this.read32(pointer + 4);
339+
this.#indexArrayIPV4[x] = Array(2);
340+
this.#indexArrayIPV4[x][0] = this.read32Row(pointer, row);
341+
this.#indexArrayIPV4[x][1] = this.read32Row(pointer + 4, row);
302342
pointer += 8;
303343
}
344+
345+
if (this.#myDB.indexedIPV6 == 1) {
346+
for (let x = 0; x < MAX_INDEX; x++) {
347+
this.#indexArrayIPV6[x] = Array(2);
348+
this.#indexArrayIPV6[x][0] = this.read32Row(pointer, row);
349+
this.#indexArrayIPV6[x][1] = this.read32Row(pointer + 4, row);
350+
pointer += 8;
351+
}
352+
}
304353
}
305354
loadOK = true;
306355
}
@@ -338,6 +387,8 @@ class IP2Proxy {
338387
this.#myDB.dbYear = 0;
339388
this.#myDB.baseAddressIPV6 = 0;
340389
this.#myDB.dbCountIPV6 = 0;
390+
this.#myDB.indexed = 0;
391+
this.#myDB.indexedIPV6 = 0;
341392
this.#myDB.indexBaseAddress = 0;
342393
this.#myDB.indexBaseAddressIPV6 = 0;
343394
this.#myDB.productCode = 0;
@@ -365,8 +416,9 @@ class IP2Proxy {
365416
let rowOffset2;
366417
let ipFrom;
367418
let ipTo;
368-
let firstCol;
419+
let firstCol = 4; // IP From is 4 bytes
369420
let row;
421+
let fullRow;
370422

371423
if (ipType == 4) {
372424
MAX_IP_RANGE = MAX_IPV4_RANGE;
@@ -375,9 +427,11 @@ class IP2Proxy {
375427
columnSize = this.#ipV4ColumnSize;
376428
ipNumber = dot2Num(myIP);
377429

378-
indexAddress = ipNumber >>> 16;
379-
low = this.#indexArrayIPV4[indexAddress][0];
380-
high = this.#indexArrayIPV4[indexAddress][1];
430+
if (this.#myDB.indexed == 1) {
431+
indexAddress = ipNumber >>> 16;
432+
low = this.#indexArrayIPV4[indexAddress][0];
433+
high = this.#indexArrayIPV4[indexAddress][1];
434+
}
381435
} else if (ipType == 6) {
382436
MAX_IP_RANGE = MAX_IPV6_RANGE;
383437
high = this.#myDB.dbCountIPV6;
@@ -400,13 +454,18 @@ class IP2Proxy {
400454
} else {
401455
ipNumber = ipNumber.not().and(LAST_32_BITS).toJSNumber();
402456
}
403-
indexAddress = ipNumber >>> 16;
404-
low = this.#indexArrayIPV4[indexAddress][0];
405-
high = this.#indexArrayIPV4[indexAddress][1];
457+
if (this.#myDB.indexed == 1) {
458+
indexAddress = ipNumber >>> 16;
459+
low = this.#indexArrayIPV4[indexAddress][0];
460+
high = this.#indexArrayIPV4[indexAddress][1];
461+
}
406462
} else {
407-
indexAddress = ipNumber.shiftRight(112).toJSNumber();
408-
low = this.#indexArrayIPV6[indexAddress][0];
409-
high = this.#indexArrayIPV6[indexAddress][1];
463+
firstCol = 16; // IPv6 is 16 bytes
464+
if (this.#myDB.indexedIPV6 == 1) {
465+
indexAddress = ipNumber.shiftRight(112).toJSNumber();
466+
low = this.#indexArrayIPV6[indexAddress][0];
467+
high = this.#indexArrayIPV6[indexAddress][1];
468+
}
410469
}
411470
}
412471

@@ -420,25 +479,23 @@ class IP2Proxy {
420479
data.ipNo = ipNumber.toString();
421480

422481
while (low <= high) {
423-
mid = parseInt((low + high) / 2);
482+
mid = Math.trunc((low + high) / 2);
424483
rowOffset = baseAddress + mid * columnSize;
425484
rowOffset2 = rowOffset + columnSize;
426485

427-
ipFrom = this.read32Or128(rowOffset, ipType);
428-
ipTo = this.read32Or128(rowOffset2, ipType);
486+
// reading IP From + whole row + next IP From
487+
fullRow = this.readRow(columnSize + firstCol, rowOffset);
488+
ipFrom = this.read32Or128Row(0, fullRow, firstCol);
489+
ipTo = this.read32Or128Row(columnSize, fullRow, firstCol);
429490

430491
ipFrom = bigInt(ipFrom);
431492
ipTo = bigInt(ipTo);
432493

433494
if (ipFrom.leq(ipNumber) && ipTo.gt(ipNumber)) {
434495
loadMesg(data, MSG_NOT_SUPPORTED); // load default message
435496

436-
firstCol = 4;
437-
if (ipType == 6) {
438-
firstCol = 16;
439-
}
440-
441-
row = this.readRow(columnSize - firstCol, rowOffset + firstCol);
497+
let rowLen = columnSize - firstCol;
498+
row = fullRow.subarray(firstCol, firstCol + rowLen); // extract the actual row data
442499

443500
if (this.#proxyTypeEnabled) {
444501
if (

0 commit comments

Comments
 (0)