javascript - การหาค่า CIDR สำหรับที่อยู่ IP เดียว (v4/v6) (TypeScript)
ฉันกำลังทำงานเกี่ยวกับโปรเจกต์โดยใช้ TypeScript และสามารถเข้าถึงการจัดเก็บข้อมูลแบบคู่คีย์-ค่าได้ ข้อกำหนดคือการค้นหาข้อมูลที่เกี่ยวข้องกับ IP เดียว (จับคู่คีย์)
โชคร้ายที่กุญแจมักจะเป็น CIDR ที่ครอบคลุม IP จำนวนมาก (เพื่อประหยัดพื้นที่เก็บข้อมูลเนื่องจากมีเรคคอร์ดจำนวนมาก) ในระหว่างการทดสอบของฉัน ฉันไม่สามารถหาค่า CIDR ที่ถูกต้องที่เป็นของ IP เฉพาะเจาะจงได้
ตัวอย่างข้อมูล:
"103.21.244.0/24" - "data, lorem ipsum, etc"
ตัวอย่าง IP ที่ต้องการหา:
"103.21.244.1"
ฉันได้ทดสอบไลบรารีหลายตัวเช่น: ip-address, ip-num, ip-to-int, ipaddr.js และอื่นๆ แต่ฉันไม่สามารถได้ผลลัพธ์ที่ต้องการ
บางทีฉันอาจโง่และไม่เข้าใจข้อกำหนด IP อย่างถูกต้อง หรือบางทีฉันอาจใช้ไลบรารีเหล่านี้ผิดวิธี โปรดชี้แนะฉันด้วย
แน่นอนต้องมีวิธีโดยไม่ต้องเรียกใช้ API ภายนอก (เช่น RIPE) และไม่ต้องเก็บที่อยู่ IP พันล้านรายการแทนที่จะเก็บเป็น CIDR ของพวกมัน
โดยพื้นฐานแล้วข้อกำหนดค่อนข้างเรียบง่าย: "ค้นหา KEY นี้ (ใน CIDR) โดยใช้ IP นี้ (v4 หรือ v6)".
ความช่วยเหลือ คำแนะนำ หรือ ตัวอย่างวิธีแก้ปัญหาใด ๆ จะได้รับการชื่นชมอย่างมาก
คำตอบ #1
ที่อยู่ IP สามารถแปลงเป็นตัวเลขเพียงตัวเดียวได้ รูปแบบ a.b.c.d เป็นเพียงการแทนค่าฐาน-256 ของตัวเลข 32 บิต แปลงทั้งที่อยู่และมาสก์เครือข่ายเป็นจำนวนเต็ม จากนั้นใช้การดำเนินการ "bitwise and" เพื่อใช้มาสก์กับที่อยู่ IP เป้าหมายและเปรียบเทียบกับที่อยู่เครือข่าย
function addrToNumber(addr)
{
return addr.split(".").reduce((acc,cur,i)=> acc += (Number(cur) << ( (3-i) * 8) ) ,0)
}
function subnetMaskToNumber(mask)
{
return (0xffffffff << (32 - Number(mask))) & 0xffffffff;
}
const cidr = "103.21.244.0/24";
const [networkAddr,subnetMask] = cidr.split("/");
const ipAddr = "103.21.244.1";
const match = (addrToNumber(ipAddr) & subnetMaskToNumber(subnetMask)) == addrToNumber(networkAddr)
console.log(match);เพื่อสร้าง CIDR ที่เป็นไปได้ทั้งหมดสำหรับที่อยู่ IP:
function addrToNumber(addr)
{
return addr.split(".").reduce((acc,cur,i)=> acc += (Number(cur) << ( (3-i) * 8) ) ,0)
}
function numberToAddr(num)
{
return `${(num >> 24) & 0xff}.${(num >> 16) & 0xff}.${(num >> 8) & 0xff}.${num & 0xff}`
}
const ipAddr = "103.21.244.1";
const ipValue = addrToNumber(ipAddr);
let possibleCIDR = [...Array(33)].map((_,i)=>{
let mask = i == 0 ? 0 : (0xffffffff << (32 - i)) >>> 0;
return `${numberToAddr(ipValue & mask)}/${i}`;
});
console.log(possibleCIDR);เพื่อสร้าง CIDR ที่เป็นไปได้สำหรับ IPv6 การบีบอัดศูนย์ไม่ได้ถูกจัดการ
const ipv6 = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
const groups = ipv6.split(":");
let possibleCIDR = [...Array(129)].map((_,i)=>{
let groupIndex = Math.floor(i / 16);
let mask = (i % 16) ? (0xffff << (16 - (i % 16))) & 0xffff : 0;
return groups.map((value,j)=>{
return (j < groupIndex ? value : j == groupIndex ? parseInt(value,16) & mask : 0).toString(16)
}).join(":") + `/${i}`;
});
console.log(possibleCIDR);