ช่วงนี้มีสายโทรเข้าที่อ้างว่าเป็นสำนักงานตรวจคนเข้าเมืองหรือตำรวจจีน บางครั้งเป็นเสียงอัตโนมัติภาษาจีน ดูไม่เหมือนสายหลอกลวงแบบสุ่มที่มุ่งเป้าคนญี่ปุ่นทั่วไป
ตอนเดินทางในจีน ผมเคยเขียนข้อมูลติดต่อที่โรงแรมและใช้หมายเลขโทรศัพท์ในการจอง หมายเลขอาจไปถึงกลุ่มมิจฉาชีพที่ใช้ภาษาจีนผ่านช่องทางใดช่องทางหนึ่ง
ผมเปิดฟังก์ชันบล็อกหมายเลขหลอกลวงและรบกวนของแอปที่สำนักงานตำรวจแห่งชาติญี่ปุ่นแนะนำไว้แล้ว แต่หมายเลขนี้ยังโทรเข้ามาได้ ระบบตรวจเทียบกับหมายเลขอันตรายที่ลงทะเบียนไว้ จึงหยุดหมายเลขใหม่หรือหมายเลขที่ยังไม่ถูกบันทึกทั้งหมดไม่ได้2
ผมแทบไม่มีเหตุให้รับสายจากต่างประเทศ จึงอยากให้สายภายในญี่ปุ่นทำงานตามปกติและปฏิเสธทุกสายที่ไม่ใช่รหัสประเทศญี่ปุ่น +81 แต่หาแอป iPhone ที่บล็อกสายต่างประเทศตามรหัสประเทศไม่ได้
ผมคิดว่าจะทำเอง โดยรับหมายเลขเป็นข้อความแล้วใช้ hasPrefix หรือ regular expression ปฏิเสธทุกอย่างนอก 81 ผมคาดว่าจะใช้เงื่อนไขคล้าย grep ได้ จึงไม่เคยคิดว่าต้องแจกแจงทุกหมายเลข
ตรวจสอบ Call Directory
Call Directory app extension ส่งรายการบล็อกให้ iOS ผ่าน CXCallDirectoryProvider.beginRequest(with:)
CXCallDirectoryPhoneNumber คือ Int64 เป็นชุดตัวเลขเริ่มจากรหัสประเทศโดยไม่มี + หรือช่องว่าง API เพิ่มได้ทีละหมายเลขเต็มเท่านั้น
context.addBlockingEntry(
withNextSequentialPhoneNumber: phoneNumber
)
ไม่มี API สำหรับ prefix, regular expression, รหัสประเทศ หรือช่วงหมายเลข ต้องเพิ่มหมายเลขเต็มแบบไม่ซ้ำและเรียงจากน้อยไปมาก แล้วเรียก completeRequest() ข้อผิดพลาดได้แก่ entriesOutOfOrder, duplicateEntries และ maximumEntriesExceeded4
extension ไม่ทำงานทุกครั้งที่มีสายเข้า Apple ระบุว่าต้องส่งข้อมูลทั้งหมดล่วงหน้า และไม่สามารถเรียก Web service ระหว่างมีสายเข้าได้3 จึงไม่มีจุดให้รัน if !number.hasPrefix("81")
รูปแบบการทำงานของ Call Directory
- ผู้ใช้เปิด extension ในการตั้งค่าบล็อกสายของ iOS
- แอปเรียก
reloadExtension(withIdentifier:) - iOS เปิด extension และส่ง context ให้
beginRequest(with:) - extension เพิ่มหมายเลขตามลำดับแล้วเรียก
completeRequest() - หลังจากนั้น iOS เป็นผู้ตรวจเทียบสาย
เมื่อ context.isIncremental เป็น true จะอัปเดตและลบแบบส่วนต่างได้ แต่ก็ยังใช้ช่วงหรือเงื่อนไขไม่ได้
เมื่อศึกษาถึงจุดนี้ ผมจึงพบว่าการบล็อกสายต่างประเทศทั้งหมดต้องแจกแจงหมายเลขแล้วโหลดเข้า Call Directory หมายเลขสากลอยู่ภายใต้มาตรฐาน ITU E.164 และยาวได้สูงสุด 15 หลักรวมรหัสประเทศ1
นี่เป็นขอบเขตบนอย่างง่าย ไม่ใช่จำนวนหมายเลขที่ถูกจัดสรรจริง พื้นที่ 15 หลักมีประมาณ 1015 แบบ การตัด +81 แทบไม่เปลี่ยนขนาด เก็บแค่ Int64 ก็ราว 8PB และเมื่อมีดัชนีอาจเป็นหลายสิบ PB ผมจึงเลิกคิดครอบคลุมทั้งหมดและจำกัดไปที่ +1 833
จำกัดเหลือ +1 833
+1 เป็นรหัสของ North American Numbering Plan ซึ่งรวมสหรัฐฯ และแคนาดา หลัง 833 เหลืออีก 7 หลัก การครอบคลุมทั้งหมดจึงต้องมี 107 = 10,000,000 รายการ
หมายเลข 64 บิตสิบล้านรายการใช้ 80,000,000 ไบต์ หรือราว 76.3MiB ขนาดประมาณ 80MB ทำได้จริงในแง่พื้นที่เก็บข้อมูล แต่ยังต้องทดสอบเพดานรายการและเวลาโหลดที่ Apple ไม่ได้เปิดเผย
Live Caller ID Lookup
Live Caller ID Lookup ติดต่อเซิร์ฟเวอร์เมื่อมีสายเข้า แต่ extension ไม่ได้รับเหตุการณ์สายเข้า LiveCallerIDLookupProtocol ให้เพียง serviceURL, tokenIssuerURL และ userTierToken5
@main
struct LookupExtension: LiveCallerIDLookupProtocol {
var context: LiveCallerIDLookupExtensionContext {
.init(serviceURL: serviceURL,
tokenIssuerURL: tokenIssuerURL,
userTierToken: token)
}
}
iOS เป็นผู้ค้นหา Oblivious HTTP ซ่อน IP, Privacy Pass ยืนยันตัวตนแบบไม่เปิดเผย และ KPIR ค้นหาหมายเลขเต็มในฐานะ keyword ที่เข้ารหัส6
บริการต้องมี HTTP POST endpoint สามรายการที่ใช้ Protocol Buffers7
| Endpoint | หน้าที่ | ข้อมูล |
|---|---|---|
/config | การตั้งค่า PIR และสถานะกุญแจ | ConfigRequest / ConfigResponse |
/key | อัปโหลด evaluation key | EvaluationKeys |
/queries | ประเมิน query ที่เข้ารหัส | Requests / Responses |
ข้อมูลบล็อกมี 1 ไบต์: 0 อนุญาต และ 1 บล็อก ข้อมูลผู้โทรใช้ CallIdentity Protocol Buffer8
เซิร์ฟเวอร์ไม่ได้รับหมายเลขแบบ plaintext จึงรัน hasPrefix("81") ไม่ได้ ยังต้องมี PIR dataset ที่ใช้หมายเลขเต็มเป็น key รวมถึงการตรวจ endpoint โดย Apple และ KPIR server
เปรียบเทียบ
| Call Directory | Live Caller ID Lookup | |
|---|---|---|
| ข้อมูล | โหลดล่วงหน้าบนอุปกรณ์ | PIR dataset บนเซิร์ฟเวอร์ |
| ค้นหา | iOS ตรวจในเครื่อง | iOS ส่ง query เข้ารหัส |
| หน่วย | หมายเลขเต็ม | รายการที่ใช้หมายเลขเต็มเป็น key |
| prefix | ไม่มี | ไม่มี callback อิสระบนเซิร์ฟเวอร์ |
คำนวณจำนวน
ใส่ prefix และจำนวนหลักทั้งหมดเพื่อคำนวณจำนวนหมายเลขเต็ม
สรุป
+1 833 เพียงช่วงเดียวทำได้: สิบล้านรายการและราว 80MB แต่บล็อกได้เฉพาะ prefix นี้ หากผู้โทรเปลี่ยนหมายเลขหรือรหัสประเทศ ก็ต้องสำรวจ สร้าง แจกจ่าย และโหลดข้อมูลใหม่
Caller ID ไม่ใช่การยืนยันตัวตนที่แข็งแรง เส้นทาง VoIP และการโอนสายอาจแสดงหมายเลขปลอมได้910 การบล็อกตามหมายเลขมีผลจำกัดต่อผู้ที่เปลี่ยนหรือปลอมหมายเลขบ่อย
การแจกแจง +1 833 ทำได้ทางเทคนิค แต่การดูแลใหม่ทุกครั้งที่หมายเลขเปลี่ยนนั้นยุ่งยาก ผมจึงหยุดทำ