Request eyeball probes separately for reliable ISP block detection
Split HTTP measurements: general probes for performance + eyeball-only probes (KT, LG U+) for SNI blocking detection. Ensures ISP probes are always included regardless of random probe selection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -244,19 +244,29 @@ interface GlobalpingRawResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MeasurementRequest {
|
||||||
|
type: 'ping' | 'http';
|
||||||
|
target: string;
|
||||||
|
eyeballOnly?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
async function createGlobalpingMeasurement(
|
async function createGlobalpingMeasurement(
|
||||||
type: 'ping' | 'http',
|
req: MeasurementRequest
|
||||||
target: string
|
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
|
const location: Record<string, unknown> = { country: 'KR' };
|
||||||
|
if (req.eyeballOnly) {
|
||||||
|
location.tags = ['eyeball-network'];
|
||||||
|
}
|
||||||
|
|
||||||
const body: Record<string, unknown> = {
|
const body: Record<string, unknown> = {
|
||||||
type,
|
type: req.type,
|
||||||
target,
|
target: req.target,
|
||||||
locations: [{ country: 'KR' }],
|
locations: [location],
|
||||||
limit: 5,
|
limit: req.eyeballOnly ? 5 : 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type === 'ping') {
|
if (req.type === 'ping') {
|
||||||
body.measurementOptions = { packets: 3 };
|
body.measurementOptions = { packets: 3 };
|
||||||
} else {
|
} else {
|
||||||
body.measurementOptions = {
|
body.measurementOptions = {
|
||||||
@@ -273,7 +283,8 @@ async function createGlobalpingMeasurement(
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
logger.warn('Globalping measurement creation failed', {
|
logger.warn('Globalping measurement creation failed', {
|
||||||
type,
|
type: req.type,
|
||||||
|
eyeballOnly: req.eyeballOnly,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
@@ -314,20 +325,28 @@ async function pollGlobalpingResult(id: string): Promise<GlobalpingRawResult[]>
|
|||||||
const SNI_BLOCK_PATTERNS = ['ECONNRESET', 'connection reset', 'socket hang up'];
|
const SNI_BLOCK_PATTERNS = ['ECONNRESET', 'connection reset', 'socket hang up'];
|
||||||
|
|
||||||
async function checkKoreaProbes(domain: string): Promise<GlobalpingProbeResult[]> {
|
async function checkKoreaProbes(domain: string): Promise<GlobalpingProbeResult[]> {
|
||||||
// Create ping and HTTP measurements in parallel
|
// Create 3 measurements in parallel:
|
||||||
const [pingId, httpId] = await Promise.all([
|
// - ping: general probes for latency
|
||||||
createGlobalpingMeasurement('ping', domain),
|
// - HTTP general: datacenter probes for performance baseline
|
||||||
createGlobalpingMeasurement('http', domain),
|
// - HTTP eyeball: ISP probes (KT, LG) for SNI block detection
|
||||||
|
const [pingId, httpId, httpEyeballId] = await Promise.all([
|
||||||
|
createGlobalpingMeasurement({ type: 'ping', target: domain }),
|
||||||
|
createGlobalpingMeasurement({ type: 'http', target: domain }),
|
||||||
|
createGlobalpingMeasurement({ type: 'http', target: domain, eyeballOnly: true }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!pingId && !httpId) return [];
|
if (!pingId && !httpId && !httpEyeballId) return [];
|
||||||
|
|
||||||
// Poll both results in parallel
|
// Poll all results in parallel
|
||||||
const [pingResults, httpResults] = await Promise.all([
|
const [pingResults, httpResults, httpEyeballResults] = await Promise.all([
|
||||||
pingId ? pollGlobalpingResult(pingId) : Promise.resolve([]),
|
pingId ? pollGlobalpingResult(pingId) : Promise.resolve([]),
|
||||||
httpId ? pollGlobalpingResult(httpId) : Promise.resolve([]),
|
httpId ? pollGlobalpingResult(httpId) : Promise.resolve([]),
|
||||||
|
httpEyeballId ? pollGlobalpingResult(httpEyeballId) : Promise.resolve([]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Combine HTTP results (eyeball + general, dedup by key)
|
||||||
|
const allHttpResults = [...httpEyeballResults, ...httpResults];
|
||||||
|
|
||||||
// Merge ping and HTTP results by probe city+network
|
// Merge ping and HTTP results by probe city+network
|
||||||
const probeMap = new Map<string, GlobalpingProbeResult>();
|
const probeMap = new Map<string, GlobalpingProbeResult>();
|
||||||
|
|
||||||
@@ -348,7 +367,7 @@ async function checkKoreaProbes(domain: string): Promise<GlobalpingProbeResult[]
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const r of httpResults) {
|
for (const r of allHttpResults) {
|
||||||
const key = `${r.probe.city}:${r.probe.network}`;
|
const key = `${r.probe.city}:${r.probe.network}`;
|
||||||
const isEyeball = (r.probe.tags || []).includes('eyeball-network');
|
const isEyeball = (r.probe.tags || []).includes('eyeball-network');
|
||||||
const existing = probeMap.get(key) || {
|
const existing = probeMap.get(key) || {
|
||||||
|
|||||||
Reference in New Issue
Block a user