ip-asn-map 1.0.0
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.
- package/BUFFER.md +27 -0
- package/README.md +73 -0
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -0
- package/dist/buffer.d.ts +23 -0
- package/dist/buffer.js +172 -0
- package/dist/buffer.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +60 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/map.d.ts +36 -0
- package/dist/map.js +157 -0
- package/dist/map.js.map +1 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +91 -0
- package/dist/test.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +33 -0
- package/dist/utils.js.map +1 -0
- package/index.html +16 -0
- package/package.json +41 -0
- package/src/browser.ts +2 -0
- package/src/buffer.ts +200 -0
- package/src/cli.ts +75 -0
- package/src/index.ts +3 -0
- package/src/map.ts +188 -0
- package/src/test.ts +104 -0
- package/src/types.ts +88 -0
- package/src/utils.ts +38 -0
- package/tsconfig.json +23 -0
package/BUFFER.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Buffer file format
|
|
2
|
+
|
|
3
|
+
All integers are little-endian. This means a uint128 is a pair of uint64's, which is convenient and less confusing.
|
|
4
|
+
|
|
5
|
+
## Header
|
|
6
|
+
|
|
7
|
+
32 bytes total, some unused
|
|
8
|
+
|
|
9
|
+
* 8 bytes = `ip-map\0\0`
|
|
10
|
+
* 5x uint32:
|
|
11
|
+
* `version` = 1
|
|
12
|
+
* `num6` = number of IPv6 entries (including 0 and ~0)
|
|
13
|
+
* `num4` = number of IPv4 entries (including 0.0.0.0 and 255.255.255.255)
|
|
14
|
+
* `asOffset` = starting offset of AS info block
|
|
15
|
+
* `bufSize` = expected total buffer size
|
|
16
|
+
|
|
17
|
+
## Data
|
|
18
|
+
|
|
19
|
+
* num6 x 16 bytes = uint128 (or a pair of uint64) for each IPv6 range *start* only (since the TSV does not seem to have holes)
|
|
20
|
+
* num4 x 4 bytes = per IPv4 range start
|
|
21
|
+
* num6 x 4 bytes = uint32 AS info record offset for IPv6 records
|
|
22
|
+
* num4 x 4 bytes = uint32 AS info record offset for IPv4 records
|
|
23
|
+
* AS records. Each record is at `asOffset` + value from previous two tables and consists of:
|
|
24
|
+
* uint32 = AS number
|
|
25
|
+
* 2 bytes = country code (or 0x0000)
|
|
26
|
+
* uint16 = description length
|
|
27
|
+
* description (if any)
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ip-asn-map
|
|
2
|
+
|
|
3
|
+
Maps IP addresses to country and AS info with low memory footprint.
|
|
4
|
+
|
|
5
|
+
* Uses the data graciously provided by [IPtoASN](https://iptoasn.com) (not included, fetch yourself as necessary).
|
|
6
|
+
* Native JS, no dependencies. The update/build code needs Node.js, but the actual `IpMap` class only uses `ArrayBuffer` and `DataView` and can probably work anywhere. I haven't checked.
|
|
7
|
+
* Memory usage: a [single blob](BUFFER.md) of about 10 MiB optimized for binary search.
|
|
8
|
+
* Lookup speed: about 250k lookups/sec or 4 microseconds per lookup on my Ryzen 5600G.
|
|
9
|
+
* Zero emojis (although I am holding back), bad grammar, and code with badly named variables and no comments. As if an actual human wasted half a weekend to write and document this by hand. Weirdo.
|
|
10
|
+
|
|
11
|
+
**Warning**: the lookup function uses a very naive parser that expects the addresses in the most basic form, 1.2.3.4 or a:b::c:d. If you're dealing with untrusted input, you should probably pass it through a proper parser first.
|
|
12
|
+
|
|
13
|
+
## Command line
|
|
14
|
+
|
|
15
|
+
Install:
|
|
16
|
+
|
|
17
|
+
npm install ip-asn-map
|
|
18
|
+
|
|
19
|
+
Fetch and process the latest dataset, and save it in the package directory:
|
|
20
|
+
|
|
21
|
+
npx ip-asn-map update
|
|
22
|
+
# or
|
|
23
|
+
npx ip-asn-map update cache/custom.bin # custom destination
|
|
24
|
+
|
|
25
|
+
Generate the blob using previously fetched TSV (any of)
|
|
26
|
+
|
|
27
|
+
npx ip-asn-map parse ip2asn-combined.tsv.gz # save to default location
|
|
28
|
+
npx ip-asn-map parse ip2asn-combined.tsv.gz cache/custom.bin
|
|
29
|
+
npx ip-asn-map parse ip2asn-combined.tsv cache/custom.bin # can be unpacked
|
|
30
|
+
zcat ip2asn-combined.tsv.gz | npx ip-asn-map parse - - > custom.bin # stdio
|
|
31
|
+
|
|
32
|
+
Lookup an address:
|
|
33
|
+
|
|
34
|
+
npx ip-asn-map lookup 51.210.240.134
|
|
35
|
+
npx ip-asn-map lookup 2001:abad:1dea:: praise.odin
|
|
36
|
+
|
|
37
|
+
Example output:
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
family: 4,
|
|
41
|
+
ip: '51.210.240.134',
|
|
42
|
+
int: 869462150,
|
|
43
|
+
as: { number: 16276, country: 'FR', description: 'OVH' },
|
|
44
|
+
range: {
|
|
45
|
+
family: 4,
|
|
46
|
+
first: '51.210.0.0',
|
|
47
|
+
last: '51.210.255.255',
|
|
48
|
+
firstInt: 869400576,
|
|
49
|
+
lastInt: 869466111,
|
|
50
|
+
size: 65536,
|
|
51
|
+
index: 73285
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
**[Full reference](https://virtulis.codeberg.page/ip-asn-map/docs/)**
|
|
58
|
+
|
|
59
|
+
In Node:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { loadIpMap } from 'ip-asn-map';
|
|
63
|
+
|
|
64
|
+
const map = await loadIpMap(); // or loadIpMap('custom.bin');
|
|
65
|
+
const result = map.lookup('51.210.240.134');
|
|
66
|
+
const cc = result.as.country; // 'FR', may be null if the range is not assigned
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
[Browser example](https://virtulis.codeberg.page/ip-asn-map/) — [index.html](./index.html)
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
Public Domain / CC0
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC"}
|
package/dist/buffer.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
import { IpMap } from './map.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Accepts a *stream of lines* from the IP2ASN combined TSV.
|
|
5
|
+
* Returns a buffer containing the encoded lookup map.
|
|
6
|
+
* @param stream
|
|
7
|
+
*/
|
|
8
|
+
export declare function encodeIp2AsnStream(stream: AsyncIterable<string>): Promise<Buffer<ArrayBuffer>>;
|
|
9
|
+
/**
|
|
10
|
+
* Helper function. Accepts a readable stream of the TSV text, splits it into lines and passes to {@link encodeIp2AsnStream}.
|
|
11
|
+
* @param stream Result of createReadStream etc
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseIp2AsnStream(stream: Readable): Promise<Buffer<ArrayBuffer>>;
|
|
14
|
+
/**
|
|
15
|
+
* Helper function. Accepts path to `ip2asn-combined.tsv.gz` and decodes it for {@link encodeIp2AsnStream}.
|
|
16
|
+
* @param src
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseIp2AsnGzip(src: string): Promise<Buffer<ArrayBuffer>>;
|
|
19
|
+
/**
|
|
20
|
+
* Load buffer from file and create an IpMap instance.
|
|
21
|
+
* @param file path to the file, assumes default location in package directory otherwise.
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadIpMap(file?: string): Promise<IpMap>;
|
package/dist/buffer.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { parseIPv4, parseIPv6 } from "./utils.js";
|
|
2
|
+
import { IpMap } from "./map.js";
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Accepts a *stream of lines* from the IP2ASN combined TSV.
|
|
6
|
+
* Returns a buffer containing the encoded lookup map.
|
|
7
|
+
* @param stream
|
|
8
|
+
*/
|
|
9
|
+
export async function encodeIp2AsnStream(stream) {
|
|
10
|
+
const list4 = [0];
|
|
11
|
+
const list6 = [BigInt(0)];
|
|
12
|
+
let last4 = 0;
|
|
13
|
+
let last6 = BigInt(0);
|
|
14
|
+
const asn4 = [0];
|
|
15
|
+
const asn6 = [0];
|
|
16
|
+
let asOffset = 0;
|
|
17
|
+
const asMap = new Map();
|
|
18
|
+
const provideAsn = (number, country, description) => {
|
|
19
|
+
const ex = asMap.get(number);
|
|
20
|
+
if (ex)
|
|
21
|
+
return ex;
|
|
22
|
+
const descBuf = description ? Buffer.from(description, 'ascii') : null; // should throw if not ascii
|
|
23
|
+
const descLen = descBuf?.length ?? 0;
|
|
24
|
+
if (descLen > 255)
|
|
25
|
+
throw new Error('Description too long');
|
|
26
|
+
const byteLen = 4 + 2 + 2 + descLen; // num + cc + len + desc
|
|
27
|
+
const as = {
|
|
28
|
+
offset: asOffset,
|
|
29
|
+
number,
|
|
30
|
+
country,
|
|
31
|
+
description,
|
|
32
|
+
};
|
|
33
|
+
asMap.set(number, as);
|
|
34
|
+
asOffset += byteLen;
|
|
35
|
+
return as;
|
|
36
|
+
};
|
|
37
|
+
provideAsn(0, null, null);
|
|
38
|
+
let i = 0;
|
|
39
|
+
let last;
|
|
40
|
+
for await (const line of stream) {
|
|
41
|
+
i++;
|
|
42
|
+
const split = line.trim().split('\t');
|
|
43
|
+
const [start, end, asNumStr, ccStr, desc] = split;
|
|
44
|
+
const cc = ccStr.length == 2 ? ccStr : null;
|
|
45
|
+
const asNum = parseInt(asNumStr, 10);
|
|
46
|
+
const as = provideAsn(asNum, cc, desc?.trim() || null);
|
|
47
|
+
if (start.match(/^\d+\./)) {
|
|
48
|
+
const int = parseIPv4(start);
|
|
49
|
+
if (int < last4)
|
|
50
|
+
throw new Error('Data out of order or read error');
|
|
51
|
+
list4.push(int);
|
|
52
|
+
asn4.push(as.offset);
|
|
53
|
+
last4 = parseIPv4(end);
|
|
54
|
+
}
|
|
55
|
+
else if (start.match(/^[0-9a-f]*:/)) {
|
|
56
|
+
const int = parseIPv6(start);
|
|
57
|
+
if (int < last6)
|
|
58
|
+
throw new Error('Data out of order or read error');
|
|
59
|
+
list6.push(int);
|
|
60
|
+
asn6.push(as.offset);
|
|
61
|
+
last6 = parseIPv6(end);
|
|
62
|
+
}
|
|
63
|
+
else if (line) {
|
|
64
|
+
console.log(line);
|
|
65
|
+
throw new Error('Unexpected input at line ' + i);
|
|
66
|
+
}
|
|
67
|
+
last = split;
|
|
68
|
+
}
|
|
69
|
+
list4.push(last4 + 1);
|
|
70
|
+
list4.push(0xffffffff);
|
|
71
|
+
list6.push(last6 + 1n);
|
|
72
|
+
list6.push(BigInt('0x' + 'f'.repeat(32)));
|
|
73
|
+
asn4.push(0, 0);
|
|
74
|
+
asn6.push(0, 0);
|
|
75
|
+
const num4 = list4.length;
|
|
76
|
+
const num6 = list6.length;
|
|
77
|
+
const hdrLen = 32;
|
|
78
|
+
const lengths = [hdrLen, num6 * 16, num4 * 4, num6 * 4, num4 * 4, asOffset];
|
|
79
|
+
const offsets = [];
|
|
80
|
+
let pos = 0;
|
|
81
|
+
for (const len of lengths) {
|
|
82
|
+
pos += len;
|
|
83
|
+
offsets.push(pos);
|
|
84
|
+
}
|
|
85
|
+
const bufSize = offsets.at(-1);
|
|
86
|
+
// console.log(...lengths);
|
|
87
|
+
// console.log(...offsets);
|
|
88
|
+
const buf = Buffer.alloc(bufSize, 0);
|
|
89
|
+
const proceed = () => {
|
|
90
|
+
const next = offsets.shift();
|
|
91
|
+
if (pos != next)
|
|
92
|
+
throw new Error(`Offset mismatch ${pos} != ${next}`);
|
|
93
|
+
};
|
|
94
|
+
const asStart = offsets.at(-2);
|
|
95
|
+
buf.write('ip-map', 0);
|
|
96
|
+
for (const [i, val] of [
|
|
97
|
+
1, // version,
|
|
98
|
+
num6,
|
|
99
|
+
num4,
|
|
100
|
+
asStart,
|
|
101
|
+
bufSize,
|
|
102
|
+
].entries()) {
|
|
103
|
+
buf.writeUInt32BE(val, 8 + i * 4);
|
|
104
|
+
}
|
|
105
|
+
pos = 32;
|
|
106
|
+
proceed();
|
|
107
|
+
for (const int of list6) {
|
|
108
|
+
buf.writeBigUInt64BE(BigInt.asUintN(64, int >> 64n), pos);
|
|
109
|
+
buf.writeBigUInt64BE(BigInt.asUintN(64, int), pos + 8);
|
|
110
|
+
pos += 16;
|
|
111
|
+
}
|
|
112
|
+
proceed();
|
|
113
|
+
for (const int of list4) {
|
|
114
|
+
buf.writeUint32BE(int, pos);
|
|
115
|
+
pos += 4;
|
|
116
|
+
}
|
|
117
|
+
for (const arr of [asn6, asn4]) {
|
|
118
|
+
proceed();
|
|
119
|
+
for (const asn of arr) {
|
|
120
|
+
buf.writeUInt32BE(asn, pos);
|
|
121
|
+
pos += 4;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
proceed();
|
|
125
|
+
for (const as of asMap.values()) {
|
|
126
|
+
pos = asStart + as.offset;
|
|
127
|
+
buf.writeUInt32BE(as.number, pos);
|
|
128
|
+
buf.write(as.country ?? '', pos + 4);
|
|
129
|
+
if (as.description) {
|
|
130
|
+
buf.writeUInt16BE(as.description.length, pos + 6);
|
|
131
|
+
buf.write(as.description, pos + 8);
|
|
132
|
+
pos += 8 + as.description.length;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
pos += 8;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
proceed();
|
|
139
|
+
return buf;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Helper function. Accepts a readable stream of the TSV text, splits it into lines and passes to {@link encodeIp2AsnStream}.
|
|
143
|
+
* @param stream Result of createReadStream etc
|
|
144
|
+
*/
|
|
145
|
+
export async function parseIp2AsnStream(stream) {
|
|
146
|
+
const { createInterface } = await import('node:readline');
|
|
147
|
+
const rl = createInterface(stream);
|
|
148
|
+
return await encodeIp2AsnStream(rl);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Helper function. Accepts path to `ip2asn-combined.tsv.gz` and decodes it for {@link encodeIp2AsnStream}.
|
|
152
|
+
* @param src
|
|
153
|
+
*/
|
|
154
|
+
export async function parseIp2AsnGzip(src) {
|
|
155
|
+
const { createReadStream } = await import('node:fs');
|
|
156
|
+
const { createGunzip } = await import('node:zlib');
|
|
157
|
+
const stream = createReadStream(src);
|
|
158
|
+
const gunzip = createGunzip();
|
|
159
|
+
stream.pipe(gunzip);
|
|
160
|
+
return await parseIp2AsnStream(gunzip);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Load buffer from file and create an IpMap instance.
|
|
164
|
+
* @param file path to the file, assumes default location in package directory otherwise.
|
|
165
|
+
*/
|
|
166
|
+
export async function loadIpMap(file) {
|
|
167
|
+
const { readFile } = await import('node:fs/promises');
|
|
168
|
+
file ??= path.join(import.meta.dirname, '../data/ip-map.bin');
|
|
169
|
+
const buf = await readFile(file);
|
|
170
|
+
return new IpMap(buf.buffer);
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
import { loadIpMap, parseIp2AsnGzip, parseIp2AsnStream } from "./buffer.js";
|
|
4
|
+
import * as process from 'node:process';
|
|
5
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { Readable } from 'node:stream';
|
|
7
|
+
import { createGunzip } from 'node:zlib';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
const [command, ...args] = process.argv.slice(2);
|
|
10
|
+
async function writeBuffer(buffer, dest) {
|
|
11
|
+
if (dest == '-') {
|
|
12
|
+
process.stdout.write(buffer);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!dest) {
|
|
16
|
+
const dir = path.join(import.meta.dirname, '../data');
|
|
17
|
+
await mkdir(dir, { recursive: true });
|
|
18
|
+
dest = path.join(dir, 'ip-map.bin');
|
|
19
|
+
console.log('Saving to', dest);
|
|
20
|
+
}
|
|
21
|
+
await writeFile(dest, buffer);
|
|
22
|
+
}
|
|
23
|
+
if (command == 'parse') {
|
|
24
|
+
if (args.length < 1)
|
|
25
|
+
throw new Error('At least a source file is expected');
|
|
26
|
+
const [src, dest] = args;
|
|
27
|
+
let buffer;
|
|
28
|
+
if (src.endsWith('.gz')) {
|
|
29
|
+
buffer = await parseIp2AsnGzip(src);
|
|
30
|
+
}
|
|
31
|
+
else if (src == '-') {
|
|
32
|
+
buffer = await parseIp2AsnStream(process.stdin);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
buffer = await parseIp2AsnStream(createReadStream(src));
|
|
36
|
+
}
|
|
37
|
+
await writeBuffer(buffer, dest);
|
|
38
|
+
}
|
|
39
|
+
else if (command == 'update') {
|
|
40
|
+
const gunzip = createGunzip();
|
|
41
|
+
const url = 'https://iptoasn.com/data/ip2asn-combined.tsv.gz';
|
|
42
|
+
console.error('Fetching', url);
|
|
43
|
+
const res = await fetch(url);
|
|
44
|
+
if (!res.ok)
|
|
45
|
+
throw new Error(res.statusText);
|
|
46
|
+
console.error('Parsing');
|
|
47
|
+
Readable.fromWeb(res.body).pipe(gunzip);
|
|
48
|
+
const buffer = await parseIp2AsnStream(gunzip);
|
|
49
|
+
await writeBuffer(buffer, args[0]);
|
|
50
|
+
}
|
|
51
|
+
else if (command == 'lookup') {
|
|
52
|
+
const fn = args[1] || path.join(import.meta.dirname, '../data/ip-map.bin');
|
|
53
|
+
const map = await loadIpMap(fn);
|
|
54
|
+
const result = map.lookup(args[0]);
|
|
55
|
+
console.log(result);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
throw new Error('Unknown command or no command given. See README.md for info.');
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
package/dist/map.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { IpInfo } from './types.ts';
|
|
2
|
+
export declare class IpMap {
|
|
3
|
+
buffer: ArrayBuffer;
|
|
4
|
+
bytes: Uint8Array;
|
|
5
|
+
view: DataView;
|
|
6
|
+
readonly ip4Count: number;
|
|
7
|
+
readonly ip6Count: number;
|
|
8
|
+
readonly asOffset: number;
|
|
9
|
+
readonly ip6View: DataView;
|
|
10
|
+
readonly ip4View: DataView;
|
|
11
|
+
readonly ip6AsView: DataView;
|
|
12
|
+
readonly ip4AsView: DataView;
|
|
13
|
+
readonly asView: DataView;
|
|
14
|
+
static version: number;
|
|
15
|
+
/**
|
|
16
|
+
* Constructs an IpMap instance using the provided ArrayBuffer with the previously generated binary data.
|
|
17
|
+
* @param buffer
|
|
18
|
+
*/
|
|
19
|
+
constructor(buffer: ArrayBuffer);
|
|
20
|
+
private getAsAtPos;
|
|
21
|
+
/**
|
|
22
|
+
* Looks up an IPv4 address in the little-endian uint32 representation (byte order as written)
|
|
23
|
+
* @param needle
|
|
24
|
+
*/
|
|
25
|
+
findV4(needle: number): IpInfo<4>;
|
|
26
|
+
/**
|
|
27
|
+
* Looks up an IPv6 address in the little-endian uint128 representation (byte order as written)
|
|
28
|
+
* @param needle
|
|
29
|
+
*/
|
|
30
|
+
findV6(needle: bigint): IpInfo<6>;
|
|
31
|
+
/**
|
|
32
|
+
* Looks up an IP address in the form 1.2.3.4 or a:b::c:d, returns {@link IpInfo}
|
|
33
|
+
* @param address
|
|
34
|
+
*/
|
|
35
|
+
lookup(address: string): IpInfo;
|
|
36
|
+
}
|
package/dist/map.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { parseIPv4, parseIPv6, stringifyIP4, stringifyIP6 } from "./utils.js";
|
|
2
|
+
export class IpMap {
|
|
3
|
+
buffer;
|
|
4
|
+
bytes;
|
|
5
|
+
view;
|
|
6
|
+
ip4Count;
|
|
7
|
+
ip6Count;
|
|
8
|
+
asOffset;
|
|
9
|
+
ip6View;
|
|
10
|
+
ip4View;
|
|
11
|
+
ip6AsView;
|
|
12
|
+
ip4AsView;
|
|
13
|
+
asView;
|
|
14
|
+
static version = 1;
|
|
15
|
+
/**
|
|
16
|
+
* Constructs an IpMap instance using the provided ArrayBuffer with the previously generated binary data.
|
|
17
|
+
* @param buffer
|
|
18
|
+
*/
|
|
19
|
+
constructor(buffer) {
|
|
20
|
+
this.buffer = buffer;
|
|
21
|
+
const bytes = this.bytes = new Uint8Array(buffer);
|
|
22
|
+
const view = this.view = new DataView(buffer);
|
|
23
|
+
new ArrayBuffer();
|
|
24
|
+
if (String.fromCharCode(...bytes.slice(0, 6)) != 'ip-map')
|
|
25
|
+
throw new Error('Not an ip-map buffer');
|
|
26
|
+
const [version, num6, num4, asOffset, bufSize] = [0, 1, 2, 3, 4].map(i => view.getUint32(8 + 4 * i));
|
|
27
|
+
if (version != IpMap.version)
|
|
28
|
+
throw new Error(`Expected file version ${IpMap.version}, got ${version}`);
|
|
29
|
+
if (buffer.byteLength != bufSize)
|
|
30
|
+
throw new Error(`Expected file size ${bufSize}, got ${buffer.byteLength}`);
|
|
31
|
+
this.ip4Count = num4;
|
|
32
|
+
this.ip6Count = num6;
|
|
33
|
+
this.asOffset = asOffset;
|
|
34
|
+
this.ip6View = new DataView(buffer, 32, num6 * 16);
|
|
35
|
+
this.ip4View = new DataView(buffer, this.ip6View.byteOffset + this.ip6View.byteLength, num4 * 4);
|
|
36
|
+
this.ip6AsView = new DataView(buffer, this.ip4View.byteOffset + this.ip4View.byteLength, num6 * 4);
|
|
37
|
+
this.ip4AsView = new DataView(buffer, this.ip6AsView.byteOffset + this.ip6AsView.byteLength, num4 * 4);
|
|
38
|
+
this.asView = new DataView(buffer, this.asOffset, buffer.byteLength - this.asOffset);
|
|
39
|
+
if (this.ip4AsView.byteOffset + this.ip4AsView.byteLength != this.asView.byteOffset)
|
|
40
|
+
throw new Error('Something *really* went wrong');
|
|
41
|
+
}
|
|
42
|
+
getAsAtPos(pos) {
|
|
43
|
+
const asNum = this.asView.getUint32(pos);
|
|
44
|
+
const ccInt = this.asView.getUint16(pos + 4);
|
|
45
|
+
const descLen = this.asView.getUint16(pos + 6);
|
|
46
|
+
const descAt = this.asOffset + pos + 8;
|
|
47
|
+
const desc = !descLen ? null : String.fromCharCode(...this.bytes.slice(descAt, descAt + descLen));
|
|
48
|
+
return {
|
|
49
|
+
number: asNum,
|
|
50
|
+
country: ccInt ? String.fromCharCode((ccInt >> 8) & 255, ccInt & 255) : null,
|
|
51
|
+
description: desc,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Looks up an IPv4 address in the little-endian uint32 representation (byte order as written)
|
|
56
|
+
* @param needle
|
|
57
|
+
*/
|
|
58
|
+
findV4(needle) {
|
|
59
|
+
if (needle < 0 || needle > 0xffff_ffff) {
|
|
60
|
+
throw new Error('Invalid IPv4 integer');
|
|
61
|
+
}
|
|
62
|
+
const view = this.ip4View;
|
|
63
|
+
let low = 0;
|
|
64
|
+
let high = this.ip4Count - 1;
|
|
65
|
+
while (high - low > 1) {
|
|
66
|
+
const at = Math.round(low + (high - low) * 0.5);
|
|
67
|
+
const addr = view.getUint32(at * 4);
|
|
68
|
+
if (addr > needle) {
|
|
69
|
+
high = at;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
low = at;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const first = view.getUint32(low * 4);
|
|
76
|
+
const next = view.getUint32(high * 4);
|
|
77
|
+
const last = next - 1;
|
|
78
|
+
const as = this.getAsAtPos(this.ip4AsView.getUint32(4 * low));
|
|
79
|
+
return {
|
|
80
|
+
family: 4,
|
|
81
|
+
ip: stringifyIP4(needle),
|
|
82
|
+
int: needle,
|
|
83
|
+
as,
|
|
84
|
+
range: {
|
|
85
|
+
family: 4,
|
|
86
|
+
first: stringifyIP4(first),
|
|
87
|
+
last: stringifyIP4(last),
|
|
88
|
+
firstInt: first,
|
|
89
|
+
lastInt: last,
|
|
90
|
+
size: next - first,
|
|
91
|
+
index: low,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Looks up an IPv6 address in the little-endian uint128 representation (byte order as written)
|
|
97
|
+
* @param needle
|
|
98
|
+
*/
|
|
99
|
+
findV6(needle) {
|
|
100
|
+
if (needle < 0n || needle >= (1n << 128n)) {
|
|
101
|
+
throw new Error('Invalid IPv6 bigint');
|
|
102
|
+
}
|
|
103
|
+
const view = this.ip6View;
|
|
104
|
+
let low = 0;
|
|
105
|
+
let high = this.ip6Count - 1;
|
|
106
|
+
const readAddr = (pos) => {
|
|
107
|
+
const a = view.getBigUint64(pos * 16);
|
|
108
|
+
const b = view.getBigUint64(pos * 16 + 8);
|
|
109
|
+
return (a << 64n) | b;
|
|
110
|
+
};
|
|
111
|
+
while (high - low > 1) {
|
|
112
|
+
const at = Math.round(low + (high - low) * 0.5);
|
|
113
|
+
const addr = readAddr(at);
|
|
114
|
+
if (addr > needle) {
|
|
115
|
+
high = at;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
low = at;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const first = readAddr(low);
|
|
122
|
+
const next = readAddr(high);
|
|
123
|
+
const last = next - 1n;
|
|
124
|
+
const as = this.getAsAtPos(this.ip6AsView.getUint32(4 * low));
|
|
125
|
+
return {
|
|
126
|
+
family: 6,
|
|
127
|
+
ip: stringifyIP6(needle),
|
|
128
|
+
int: needle,
|
|
129
|
+
as,
|
|
130
|
+
range: {
|
|
131
|
+
family: 6,
|
|
132
|
+
first: stringifyIP6(first),
|
|
133
|
+
last: stringifyIP6(last),
|
|
134
|
+
firstInt: first,
|
|
135
|
+
lastInt: last,
|
|
136
|
+
size: next - first,
|
|
137
|
+
index: low,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Looks up an IP address in the form 1.2.3.4 or a:b::c:d, returns {@link IpInfo}
|
|
143
|
+
* @param address
|
|
144
|
+
*/
|
|
145
|
+
lookup(address) {
|
|
146
|
+
if (address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)) {
|
|
147
|
+
return this.findV4(parseIPv4(address));
|
|
148
|
+
}
|
|
149
|
+
else if (address.match(/^([0-9a-f]*):/)) {
|
|
150
|
+
return this.findV6(parseIPv6(address));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
throw new Error('Unexpected address format');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=map.js.map
|
package/dist/map.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../src/map.ts"],"names":[],"mappings":"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"}
|
package/dist/test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|