asOrganization trên Cloudflare không phải tên nhà mạng: lấy tên đúng từ sổ đăng ký ASN
Ô ISP trên công cụ IP lookup của mình từng hiện dòng "ETT KYIV POP #1 ext.". Có chữ KYIV, có POP, có số thứ tự. Ai nhìn vào cũng hiểu: "à, công cụ nói mình đang ở Kyiv".
Chuỗi đó đến từ request.cf.asOrganization của Cloudflare. Bài này kể vì sao giá trị asOrganization Cloudflare trả về không nên đưa thẳng lên giao diện như tên nhà mạng, và cách lấy tên đúng từ sổ đăng ký ASN.
Mình là Katia, người làm ra MyIPScan, một trang công cụ IP miễn phí chạy trên Cloudflare Pages và Workers. Lỗi này là của mình: mình đã tin một trường dữ liệu đúng như tên của nó.
Vì sao một cái nhãn sai lại đáng sửa
Người xem đọc "KYIV POP" thành vị trí của họ. Với một công cụ người ta dùng để kiểm tra IP và VPN, một vị trí sai còn tệ hơn một ô trống. Ô trống thì người ta biết là thiếu. Vị trí sai thì người ta tin.
Lỗi kiểu này không làm crash gì cả. Không exception, không log đỏ, test vẫn xanh. Nó chỉ nằm đó, trông hợp lý, cho tới khi có người đọc nó theo nghĩa đen.
asOrganization Cloudflare thực ra hứa gì
Trong Cloudflare Workers, mỗi request có object request.cf chứa metadata do Cloudflare gắn vào. Tài liệu Request, phần IncomingRequestCfProperties, mô tả hai trường mình dùng:
asn: "ASN of the incoming request, for example,395747."asOrganization: "The organization which owns the ASN of the incoming request, for example,Google Cloud."
Docs hứa tên tổ chức sở hữu ASN, và ví dụ là một tên thương hiệu gọn gàng. Nhưng với mạng của Eurotranstelecom, trường này trả về "ETT KYIV POP #1 ext.". Trông như nhãn của một node mạng (POP thường là viết tắt của point of presence), chứ không phải tên công ty. Mình không biết Cloudflare lấy chuỗi này từ đâu, nên không thể ngồi chờ họ sửa.
Vị trí có trường riêng: city, country và colo (mã sân bay IATA của data center nhận request). Chữ "KYIV" ở đây nằm trong trường tổ chức, không phải trong city.
Hai giả thuyết dễ đến, và vì sao chúng không giúp
Nếu bạn gặp lỗi tương tự, hai cách giải thích dễ đến đầu tiên là:
- "Geolocation lệch, IP này thật ra được định vị ở Kyiv." Nhưng chuỗi nằm trong trường tổ chức. Đổi nhà cung cấp geolocation không làm nó biến mất.
- "Cloudflare trả sai, báo họ rồi chờ." Có thể báo, nhưng bạn không kiểm soát nguồn đó, và ASN tiếp theo có thể mang một nhãn lạ khác.
Câu hỏi đúng hơn: ai là nguồn chính thức cho câu "ASN này thuộc về ai"? Đó là sổ đăng ký số AS của các RIR (RIPE NCC, APNIC, ARIN...). Một cách đọc nó qua API, miễn phí, không cần key, là RIPEstat.
Tên nhà mạng theo ASN: đọc từ sổ đăng ký
Endpoint RIPEstat as-overview trả về trường holder cho một ASN. Với AS35320, giá trị là ETT-AS Eurotranstelecom Ltd. Không có chữ Kyiv nào.
RIPEstat trả dữ liệu cả cho ASN ngoài khu vực RIPE, nên các nhà mạng Việt Nam cũng tra được. Đây là các chuỗi holder mình kiểm tra ngày 10/11/2026, và kết quả của hàm cleanHolder ở phần dưới (chạy bằng node):
| ASN | holder trong sổ đăng ký |
Sau cleanHolder |
|---|---|---|
| AS35320 | ETT-AS Eurotranstelecom Ltd | Eurotranstelecom |
| AS6849 | UKRTELNET JSC "Ukrtelecom" | Ukrtelecom |
| AS12389 | ROSTELECOM-AS PJSC Rostelecom | Rostelecom |
| AS7552 | VIETEL-AS-AP - Viettel Group | Viettel Group |
| AS45899 | VNPT-AS-VN - VNPT Corp | VNPT |
| AS18403 | FPT-VN - FPT Telecom Company | FPT Telecom Company |
| AS13335 | CLOUDFLARENET - Cloudflare, Inc. | Cloudflare |
Chuỗi holder cũng không đẹp. Nó có handle (ETT-AS, VIETEL-AS-AP) và loại hình pháp nhân (Ltd, PJSC, Corp, Inc.). Trong bảng này, ASN của RIPE có dạng HANDLE Tên, còn các ASN còn lại có dạng HANDLE - Tên.
Handle là định danh, không phải tên. VIETEL-AS-AP chỉ có một chữ T, còn phần tên viết đúng "Viettel Group". Đừng hiển thị handle cho người dùng.
Code: Worker đọc ASN, tra RIPEstat, làm sạch tên
Đoạn dưới đây là bản minh họa rút gọn, không phải code production của MyIPScan. Ý tưởng: lấy asn từ Cloudflare, lấy tên từ sổ đăng ký, và nếu tra không được thì hiện số ASN chứ không quay lại asOrganization.
// Minh họa: Cloudflare Worker, tên nhà mạng lấy theo ASN từ RIPEstat
export default {
async fetch(request) {
const asn = request.cf?.asn ?? null;
const holder = asn ? await ripeHolder(asn) : null;
return Response.json({
asn,
// Không tra được thì hiện "AS35320", không đoán bằng asOrganization
network: holder ? cleanHolder(holder) : asn ? `AS${asn}` : null,
networkSource: holder ? "RIPEstat" : null,
});
},
};
async function ripeHolder(asn) {
const url = "https://stat.ripe.net/data/as-overview/data.json" +
`?resource=AS${asn}&sourceapp=my-ip-tool`;
try {
const res = await fetch(url, {
signal: AbortSignal.timeout(1500), // RIPEstat chậm thì bỏ, không chặn response
cf: { cacheTtl: 86400, cacheEverything: true }, // holder hiếm khi đổi
});
if (!res.ok) return null;
const body = await res.json();
return body?.data?.holder || null;
} catch {
return null; // lỗi mạng hoặc hết 1,5 giây
}
}
const LEGAL = /(^|[\s,])(PrJSC|PJSC|OJSC|CJSC|JSC|LLC|Ltd|Inc|Corp|GmbH)\.?(?=[\s,]|$)/gi;
function cleanHolder(holder) {
// 1. Tên trong ngoặc kép: UKRTELNET JSC "Ukrtelecom" -> Ukrtelecom
const quoted = holder.match(/["“]([^"”]+)["”]/);
if (quoted) return quoted[1].trim();
// 2. Bỏ handle: dạng "HANDLE - Tên" hoặc "XXX-AS Tên"
let name = holder.includes(" - ")
? holder.split(" - ").slice(1).join(" - ")
: holder.replace(/^\S*-AS\S*\s+/i, "");
// 3. Bỏ loại hình pháp nhân, rồi dấu câu thừa ở hai đầu
name = name
.replace(LEGAL, " ")
.replace(/\s+/g, " ")
.replace(/^[\s,.;:-]+|[\s,.;:-]+$/g, "");
return name || holder;
}
Vài ghi chú về đoạn code:
asOrganizationkhông có trong JSON trả về. Nếu muốn so sánh hai nguồn, ghi nó vào log phía server, đừng gửi xuống client.sourceapplà tham số RIPEstat khuyến khích người dùng API thường xuyên thêm vào để họ nhận diện ứng dụng. Thaymy-ip-toolbằng tên dự án của bạn (chỉ chữ, số, gạch nối, gạch dưới).- Cache theo ASN. Số ASN khác nhau mà một trang nhận được ít hơn nhiều so với số request.
Mình đã chạy cleanHolder trên bảy chuỗi trong bảng, cộng thêm một chuỗi tự đặt VODAFONE-UA-AS PrJSC VF UKRAINE để thử PrJSC (kết quả: VF UKRAINE). Chỉ chừng đó, không hơn. Handle không chứa -AS và không có " - " sẽ giữ nguyên, đó là chủ ý: thà hiện hơi dài còn hơn cắt nhầm.
Hàm này cũng không cố biến "Viettel Group" thành "Viettel", vì đoán bớt chữ là cách nhanh nhất để tạo ra một lỗi mới. Nếu cần tên ngắn hơn cho vài ASN lớn, một bảng ánh xạ thủ công nhỏ an toàn hơn regex thông minh.
Kiểm tra lại sau khi sửa
Cách kiểm tra đơn giản: lấy ASN, mở endpoint as-overview trên trình duyệt, so holder với tên trên giao diện. Nếu tên hiển thị không suy ra được từ holder bằng một quy tắc bạn giải thích được, thì vẫn còn chỗ đang đoán.
Nếu muốn có thêm một chỗ để đối chiếu, trang ASN Lookup trên MyIPScan hiện chủ sở hữu mạng, các prefix BGP đang hoạt động và RIR cấp số, với nguồn là RIPEstat và thời điểm tra cứu.
Quy tắc mang về
Trường nào có chữ "organization" chưa chắc là tên tổ chức. Với câu hỏi "IP này thuộc nhà mạng nào", nguồn chuẩn là sổ đăng ký ASN, còn metadata của CDN chỉ là gợi ý. Lấy tên từ holder theo ASN, làm sạch bằng quy tắc đã thử trên dữ liệu thật, luôn hiển thị kèm số ASN và nguồn, và khi không tra được thì hiện số ASN thay vì một chuỗi mình không hiểu.
All Rights Reserved