网站运营与规划,网站开发工作总结论文,烟台免费网站建站模板,国外 做励志视频的网站最近因为业务需要#xff0c;要判断用户的IP是否私有IP#xff0c; 以前知道的私有IP#xff0c;基本上只有如下几个(注意#xff1a;这不是正确答案)#xff1a;
10.0.0.0/8#xff08;10.0.0.0-10.255.255.255#xff09;172.16.0.0/12#xff08;172.16.0.0-172.31…最近因为业务需要要判断用户的IP是否私有IP 以前知道的私有IP基本上只有如下几个(注意这不是正确答案)
10.0.0.0/810.0.0.0-10.255.255.255172.16.0.0/12172.16.0.0-172.31.255.255192.168.0.0/16192.168.0.0-192.168.255.255再加一个本地IP 127.0.0.0/8127.0.0.0-127.255.255.255 localhost以前考MCSE的时候还知道一个Windows在DHCP未获取到IP时会自动分配的 169.254.0.0/16169.254.0.0-169.254.255.255
之前知道的就这些了问了一下ChatGPT老师说还有一些如图 基于以往印象中GPT老师的不靠谱情况去google查了一些资料最后搜索到官方的定义文档对互联网保留地址做了一个清单说明还贴心的提供了csv格式下载 https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
这个网址是iana的官方网站iana负责全球的IP地址分配具体说明参考百度百科 IANA ( Internet Assigned Numbers Authority互联网号码分配机构)负责协调全球DNS的根域名、IP地址分配和其他互联网协议资源。
不过iana给的清单还有一些重复维基百科帮它做了一下合并整理为17项参考地址 https://en.wikipedia.org/wiki/Reserved_IP_addresses
IP地址段IP范围IP个数范围说明0.0.0.0/80.0.0.0–0.255.255.25516,777,216Software一般用于当前网络或路由等特殊用途10.0.0.0/810.0.0.0–10.255.255.25516,777,216Private network用于大型的私有网络本地通信100.64.0.0/10100.64.0.0–100.127.255.2554,194,304Private network运营商NAT用即ISP与客户间通信的地址127.0.0.0/8127.0.0.0–127.255.255.25516,777,216Host本地主机环回地址。169.254.0.0/16169.254.0.0–169.254.255.25565,536Subnet一般在DHCP无法获取到地址时为本机分配的地址172.16.0.0/12172.16.0.0–172.31.255.2551,048,576Private network用于中型的私有网络本地通信。192.0.0.0/24192.0.0.0–192.0.0.255256Private networkIETF协议分配。192.0.2.0/24192.0.2.0–192.0.2.255256Documentation分配为TEST-NET-1做文档和示例192.88.99.0/24192.88.99.0–192.88.99.255256Internet保留。以前用于从IPv6到IPv4中继192.168.0.0/16192.168.0.0–192.168.255.25565,536Private network用于小型的私有网络本地通信。198.18.0.0/15198.18.0.0–198.19.255.255131,072Private network用于对2个独立子网间的通信通过基准测试198.51.100.0/24198.51.100.0–198.51.100.255256Documentation分配为TEST-NET-2做文档和示例203.0.113.0/24203.0.113.0–203.0.113.255256Documentation分配为TEST-NET-2做文档和示例224.0.0.0/4224.0.0.0–239.255.255.255268,435,456Internet用于IP多播以前的D类网络233.252.0.0/24233.252.0.0–233.252.0.255256Documentation指定为 MCAST-TEST-NET文档和示例240.0.0.0/4240.0.0.0–255.255.255.254268,435,455Internet保留以备将来使用以前的E类网络255.255.255.255/32255.255.255.2551Subnet保留用于“有限广播”目标地址
注 IPv6的保留地址参考这里 https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml # 转换代码
文章的最后贴一些转换用的代码吧
Javascript版本的代码
有5个方法可以看下面代码的注释
/*** 判断给定的ip是否属于 IANA定义的保留地址即私有地址* param ip 给定的ip* returns {boolean} 是否私有地址*/
function isPrivateIpAddr(ip) {const privateIp [[0.0.0.0, 0.255.255.255], // 0.0.0.0/8[10.0.0.0, 10.255.255.255], // 10.0.0.0/8[100.64.0.0, 100.127.255.255], // 100.64.0.0/10[127.0.0.0, 127.255.255.255], // 127.0.0.0/8[169.254.0.0, 169.254.255.255], // 169.254.0.0/16[172.16.0.0, 172.31.255.255], // 172.16.0.0/12[192.0.0.0, 192.0.0.255], // 192.0.0.0/24[192.0.2.0, 192.0.2.255], // 192.0.2.0/24[192.88.99.0, 192.88.99.255], // 192.88.99.0/24[192.168.0.0, 192.168.255.255], // 192.168.0.0/16[198.18.0.0, 198.19.255.255], // 198.18.0.0/15[198.51.100.0, 198.51.100.255], // 198.51.100.0/24[203.0.113.0, 203.0.113.255], // 203.0.113.0/24[224.0.0.0, 239.255.255.255], // 224.0.0.0/4[233.252.0.0, 233.252.0.255], // 233.252.0.0/24[240.0.0.0, 255.255.255.254], // 240.0.0.0/4[255.255.255.255, 255.255.255.254], // 255.255.255.255/32];for (const [startIP, endIP] of privateIp) {if (inIpAddrRange(ip, startIP, endIP)) {return true;}}return false;
}/*** 把 x.x.x.x形式的IP地址转换为整数返回* 注转换为无符号整型如 255.255.255.255转为4294967295* 即 (255*256*256*256) (255*256*256) (255*256) 255* param ip 字符串格式的ip* returns {number} 无符号整数*/
function ipaddrToNumber(ip) {//return (ip.split(.).reduce((acc, cur) (acc 8) parseInt(cur), 0)) 0;const ipArr ip.split(.);if (ipArr.length ! 4)throw new Error(IP地址格式不对应该有3个小数点);let ret 0;// 验证每个项是否小于等于255for (let i 0; i 4; i) {const number parseInt(ipArr[i], 10);if (isNaN(number) || number 255 || number 0)throw new Error(IP地址中的每个项都应在0~255之间);ret (ret 8) number;}// 转无符号数避免负数返回return ret 0;
}/*** 把一个无符号整数转换为ip地址返回* param number ipaddrToNumber方法计算得出的无符号整数* returns {string} ip地址*/
function numberToIpAddr(number) {if (number 0 || number 4294967295) {throw new Error(参数应在0~4294967295之间);}const ipArr [];for (let i 3; i 0; i--) {ipArr[i] (number (8 * (3 - i))) 255;}return ipArr.join(.);
}/*** 给定的ip是否在给定的ip起止范围内* param ip 要判断的ip* param startIP ip范围起始值* param endIp ip范围结束值* returns {boolean} 是否在范围内*/
function inIpAddrRange(ip, startIP, endIp) {const ipNum ipaddrToNumber(ip);const startIPNum ipaddrToNumber(startIP);const endIPNum ipaddrToNumber(endIp);return ipNum startIPNum ipNum endIPNum;
}/*** 给定的ip是否在给定的CIDR ip地址范围内* CIDR是用ip网址子网掩码的表示法如 192.168.0.0/16* param ip 要判断的ip* param startIP ip网址起始值* param ipMaskNum 子网掩码* returns {boolean} 是否在范围内*/
function inIpAddrCIDR(ip, startIP, ipMaskNum) {const ipMask parseInt(ipMaskNum, 10);if (isNaN(ipMask) || ipMask 1 || ipMask 32)throw new Error(子网掩码应在1~32之间);const ipNum ipaddrToNumber(ip);const startIPNum ipaddrToNumber(startIP);const endIPNum startIPNum (Math.pow(2, 32 - ipMask) - 1);console.log(startIPNum : endIPNum);return ipNum startIPNum ipNum endIPNum;
}测试代码 isPrivateIpAddr(192.168.0.1) 结果为 true ipaddrToNumber(192.168.0.1) 结果为 3232235521 ipaddrToNumber(1.2.3.4) 结果为 16909060 ipaddrToNumber(255.255.255.255) 结果为 4294967295
MySQL的代码
查了一下官方文档发现MySQL内置了 ip 和 number 互转的函数文档链接
SELECT INET_ATON(192.168.0.1) ip1,INET_ATON(1.2.3.4) ip2, INET_ATON(255.255.255.255) ip3, INET_NTOA(16909060) ip4;上面sql得到的结果如下
ip1ip2ip3ip432322355211690906042949672951.2.3.4
跟上面Javascript代码的结果是一致的。 我们只要把私有地址写入一张表再把某个ip转数字后去这张表查询是否有范围内的记录即可。
建表
CREATE TABLE sysprivateips (id bigint NOT NULL AUTO_INCREMENT COMMENT 主键,ipStart varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT COMMENT ip段起始值,ipEnd varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT COMMENT ip段结束值,ipMask tinyint NOT NULL DEFAULT 0 COMMENT 掩码暂时未用,createTime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,ipStartNum bigint GENERATED ALWAYS AS (inet_aton(ipStart)) VIRTUAL,ipEndNum bigint GENERATED ALWAYS AS (inet_aton(ipEnd)) VIRTUAL,PRIMARY KEY (id),UNIQUE KEY uqi_ip (ipStartNum)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci ROW_FORMATDYNAMIC COMMENT私有ip列表插入所有的私有IP数据
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(0.0.0.0, 0.255.255.255, 8);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(10.0.0.0, 10.255.255.255, 8);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(100.64.0.0, 100.127.255.255, 10);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(127.0.0.0, 127.255.255.255, 8);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(169.254.0.0, 169.254.255.255, 16);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(172.16.0.0, 172.31.255.255, 12);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(192.0.0.0, 192.0.0.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(192.0.2.0, 192.0.2.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(192.88.99.0, 192.88.99.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(192.168.0.0, 192.168.255.255, 16);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(198.18.0.0, 198.19.255.255, 15);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(198.51.100.0, 198.51.100.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(203.0.113.0, 203.0.113.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(224.0.0.0, 239.255.255.255, 4);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(233.252.0.0, 233.252.0.255, 24);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(240.0.0.0, 255.255.255.254, 4);
INSERT INTO sysprivateips(ipStart,ipEnd,ipMask)VALUES(255.255.255.255, 255.255.255.254, 32);OK现在可以直接用sql判断是否私有IP了 假设要查看 192.168.0.1对应的CIDR地址段用这个sql
SELECT CONCAT(ipStart, /, ipMask) AS CIDR FROM sysprivateipsWHERE ipStartNumINET_ATON(192.168.0.1) AND INET_ATON(192.168.0.1)ipEndNum