Skip to content

Commit 201bfc9

Browse files
committed
feat: use ip2location for hosting detection, allow manual overrides
1 parent 3b702d8 commit 201bfc9

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

Diff for: src/lib/geoip/client.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { fastlyLookup } from './providers/fastly.js';
1414
import { maxmindLookup } from './providers/maxmind.js';
1515
import { ipmapLookup } from './providers/ipmap.js';
1616
import { type Ip2LocationBundledResponse, ip2LocationLookup } from './providers/ip2location.js';
17+
import { isHostingOverrides } from './overrides.js';
1718

1819
export type LocationInfo = Omit<ProbeLocation, 'region'>;
1920
type Provider = 'ipmap' | 'ip2location' | 'ipinfo' | 'maxmind' | 'fastly';
@@ -42,7 +43,7 @@ export default class GeoipClient {
4243
this.lookupWithCache<LocationInfo>(`geoip:fastly:${addr}`, async () => fastlyLookup(addr)),
4344
])
4445
.then(([ ipinfo, ip2location, maxmind, ipmap, fastly ]) => {
45-
isHosting = ipinfo.status === 'fulfilled' ? ipinfo.value.isHosting : undefined;
46+
isHosting = ip2location.status === 'fulfilled' ? ip2location.value.isHosting : undefined;
4647
const fulfilled: (LocationInfoWithProvider | null)[] = [];
4748

4849
// Providers here are pushed in a desc prioritized order
@@ -74,6 +75,13 @@ export default class GeoipClient {
7475
throw new ProbeError(`unresolvable geoip: ${addr}`);
7576
}
7677

78+
for (const override of isHostingOverrides) {
79+
if (override.normalizedNetwork.test(networkMatch.normalizedNetwork)) {
80+
isHosting = override.isHosting;
81+
break;
82+
}
83+
}
84+
7785
const region = getRegionByCountry(match.country);
7886

7987
return {

Diff for: src/lib/geoip/overrides.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const isHostingOverrides = [
2+
// https://baxetgroup.com/
3+
{
4+
normalizedNetwork: /baxet group/,
5+
isHosting: true,
6+
},
7+
// https://www.psychz.net/
8+
{
9+
normalizedNetwork: /psychz networks/,
10+
isHosting: true,
11+
},
12+
];

Diff for: src/lib/geoip/providers/ip2location.ts

+5
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ type Ip2LocationResponse = {
2525
longitude?: number;
2626
as?: string;
2727
is_proxy?: boolean;
28+
usage_type?: string;
2829
};
2930

3031
export type Ip2LocationBundledResponse = {
3132
location: LocationInfo,
33+
isHosting: boolean | undefined,
3234
isProxy: boolean,
3335
};
3436

37+
const HOSTING_USAGE_TYPES = [ 'CDN', 'DCH' ];
38+
3539
export const ip2LocationLookup = async (addr: string): Promise<Ip2LocationBundledResponse> => {
3640
const result = await got(`https://api.ip2location.io`, {
3741
searchParams: {
@@ -58,6 +62,7 @@ export const ip2LocationLookup = async (addr: string): Promise<Ip2LocationBundle
5862

5963
return {
6064
location,
65+
isHosting: result.usage_type ? HOSTING_USAGE_TYPES.includes(result.usage_type) : undefined,
6166
isProxy: result.is_proxy ?? false,
6267
};
6368
};

Diff for: test/mocks/nock-geoip.json

+10-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"longitude": -96.8067,
99
"asn": "20001",
1010
"as": "The Constant Company LLC",
11-
"is_proxy": false
11+
"is_proxy": false,
12+
"usage_type": "DCH"
1213
},
1314
"argentina": {
1415
"country_code": "AR",
@@ -28,7 +29,8 @@
2829
"longitude": -74.0060,
2930
"asn": "80001",
3031
"as": "The Constant Company LLC",
31-
"is_proxy": false
32+
"is_proxy": false,
33+
"usage_type": "CDN"
3234
},
3335
"washington": {
3436
"country_code": "US",
@@ -37,7 +39,8 @@
3739
"latitude": 38.89539,
3840
"longitude": -77.039476,
3941
"asn": "40676",
40-
"as": "Psychz Networks"
42+
"as": "Psychz Networks",
43+
"usage_type": "ISP"
4144
},
4245
"falkenstein": {
4346
"country_code": "DE",
@@ -102,7 +105,8 @@
102105
"longitude": -96.8067,
103106
"asn": "20001",
104107
"as": "The Constant Company LLC",
105-
"is_proxy": true
108+
"is_proxy": true,
109+
"usage_type": "DCH"
106110
},
107111
"noVpn": {
108112
"country_code": "US",
@@ -111,7 +115,8 @@
111115
"latitude": 32.7831,
112116
"longitude": -96.8067,
113117
"asn": "20001",
114-
"as": "The Constant Company LLC"
118+
"as": "The Constant Company LLC",
119+
"usage_type": "DCH"
115120
}
116121
},
117122
"ipmap": {

Diff for: test/tests/unit/geoip/client.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ describe('geoip service', () => {
161161
longitude: -58.3772,
162162
network: 'InterBS S.R.L. (BAEHOST)',
163163
normalizedNetwork: 'interbs s.r.l. (baehost)',
164-
isHosting: undefined,
164+
isHosting: true,
165165
});
166166
});
167167

@@ -427,7 +427,7 @@ describe('geoip service', () => {
427427
longitude: -77.039476,
428428
network: 'Psychz Networks',
429429
normalizedNetwork: 'psychz networks',
430-
isHosting: undefined,
430+
isHosting: true,
431431
});
432432

433433
nockGeoIpProviders({ ip2location: 'empty', ipmap: 'empty', maxmind: 'empty', ipinfo: 'washington', fastly: 'empty' });
@@ -446,7 +446,7 @@ describe('geoip service', () => {
446446
longitude: -77.039476,
447447
network: 'Verizon Business',
448448
normalizedNetwork: 'verizon business',
449-
isHosting: false,
449+
isHosting: undefined,
450450
});
451451
});
452452

0 commit comments

Comments
 (0)