Python 判断内网ip的实现方法
一、背景
一般在CMDB(Configuration Management Database,配置管理数据库)里会存储一台服务器的内网IP、私有IP、管理IP、电信IP、联通IP、BAT弹性IP,在使用的时候只需要拿到其中一个外网IP地址即可。那么我们就需要判断并剔除掉内网IP、私有IP、管理IP,获取第一个外网IP(电信IP、联通IP、BAT弹性IP)。
例如三线机房服务器:'10.20.0.111'(内网IP), '10.10.42.1'(管理IP), '100.64.228.13'(运营商IP), '221.222.222.33', '8.8.8.8(DNS解析)', '114.114.144.114', '192.168.31.46'(内网IP)
二、判断内网ip的原理
内网IP可分为三类:
A类地址:10.0.0.0--10.255.255.255
B类地址:172.16.0.0--172.31.255.255
C类地址:192.168.0.0--192.168.255.255
运营商:100.64.0.0/10 100.64.0.0--100.127.255.255
DHCP: 169.254.0.0/16 169.254.0.0--169.254.255.255
局域网在选取使用私有地址时,一般会按照实际需要容纳的主机数来选择私有地址段。
常见的局域网由于容量小,一般选择C类的192.168.0.0作为地址段使用,一些大型企业就需要使用B类甚至A类地址段作为内部网络的地址段。
首地址 | 尾地址 | 所属IP分类 | 无分类掩码 | 示意 |
0.0.0.0 | 0.255.255.255 | Class A network 0.x.x.x | 0.0.0.0/8 | A类保留地址 |
10.0.0.0 | 10.255.255.255 | Class A network 10.x.x.x | 10.0.0.0/8 | A类私有地址 |
100.64.0.0 | 100.127.255.255 | Class B network 100.x.x.x | 100.64.0.0/10 | 64个B类私有地址(运营商) |
127.0.0.0 | 127.255.255.255 | Class A network 127.x.x.x | 127.0.0.0/8 | 回环IP,表示本机 |
128.0.0.0 | 128.0.255.255 | Class B network 128.0.x.x | 128.0.0.0/16 | 保留 |
169.254.0.0 | 169.254.255.255 | Class B network 169.254.x.x | 169.254.0.0/16 | DHCP自动分配B类私有IP地址 |
172.16.0.0 | 172.31.255.255 | 172.16.x.x 到 172.31.x.x共16共B类网络 | 172.16.0.0/12 | B类私有地址 |
191.255.0.0 | 191.255.255.255 | Class B network 191.255.x.x | 191.255.0.0/16 | C类保留地址 |
192.0.0.0 | 192.0.0.255 | Class C network 192.0.0.x | 192.0.0.0/24 | C类保留地址 |
192.168.0.0 | 192.168.255.255 | 256 个C类网络 | 192.168.0.0/16 | C类私有IP |
223.255.255.0 | 223.255.255.255 | Class C network 223.255.255.x | 223.255.255/24 | 保留 |
255.255.255.255 | 255.255.255.255 | Class C network 255.255.255.255 | 255.255.255.255/32 | 广播地址 |
更完整的保留IP:维基百科的Reserved IP Address词条
Address block | Address range | Number of addresses | Scope | Description |
---|---|---|---|---|
0.0.0.0/8 | 0.0.0.0–0.255.255.255 | 777216 16 | Software | Current network (only valid as source address). |
10.0.0.0/8 | 10.0.0.0–10.255.255.255 | 777216 16 | Private network | Used for local communications within a private network. |
100.64.0.0/10 | 100.64.0.0–100.127.255.255 | 194304 4 | Private network | Shared address space for communications between a service provider and its subscribers when using a carrier-grade NAT. |
127.0.0.0/8 | 127.0.0.0–127.255.255.255 | 777216 16 | Host | Used for loopback addresses to the local host. |
169.254.0.0/16 | 169.254.0.0–169.254.255.255 | 536 65 | Subnet | Used for link-local addresses between two hosts on a single link when no IP address is otherwise specified, such as would have normally been retrieved from a DHCP server. |
172.16.0.0/12 | 172.16.0.0–172.31.255.255 | 048576 1 | Private network | Used for local communications within a private network. |
192.0.0.0/24 | 192.0.0.0–192.0.0.255 | 256 | Private network | IETF Protocol Assignments. |
192.0.2.0/24 | 192.0.2.0–192.0.2.255 | 256 | Documentation | Assigned as TEST-NET-1, documentation and examples. |
192.88.99.0/24 | 192.88.99.0–192.88.99.255 | 256 | Internet | Reserved. Formerly used for IPv6 to IPv4 relay (included IPv6 address block 2002::/16). |
192.168.0.0/16 | 192.168.0.0–192.168.255.255 | 536 65 | Private network | Used for local communications within a private network. |
198.18.0.0/15 | 198.18.0.0–198.19.255.255 | 072 131 | Private network | Used for benchmark testing of inter-network communications between two separate subnets. |
198.51.100.0/24 | 198.51.100.0–198.51.100.255 | 256 | Documentation | Assigned as TEST-NET-2, documentation and examples. |
203.0.113.0/24 | 203.0.113.0–203.0.113.255 | 256 | Documentation | Assigned as TEST-NET-3, documentation and examples. |
224.0.0.0/4 | 224.0.0.0–239.255.255.255 | 435456 268 | Internet | In use for IP multicast. (Former Class D network). |
240.0.0.0/4 | 240.0.0.0–255.255.255.254 | 435456 268 | Internet | Reserved for future use. (Former Class E network). |
255.255.255.255/32 | 255.255.255.255 | 1 | Subnet | Reserved for the "limited broadcast" destination address. |
三、代码实现步骤
实现方法一:掩码对比
def ip_into_int(ip): # 先把 192.168.31.46 用map分割'.'成数组,然后用reduuce+lambda转成10进制的 3232243502 # (((((192 * 256) + 168) * 256) + 31) * 256) + 46 return reduce(lambda x,y:(x<<8)+y,map(int,ip.split('.'))) # 方法1:掩码对比 def is_internal_ip(ip_str): ip_int = ip_into_int(ip_str) net_A = ip_into_int('10.255.255.255') >> 24 net_B = ip_into_int('172.31.255.255') >> 20 net_C = ip_into_int('192.168.255.255') >> 16 net_ISP = ip_into_int('100.127.255.255') >> 22 net_DHCP = ip_into_int('169.254.255.255') >> 16 return ip_int >> 24 == net_A or ip_int >>20 == net_B or ip_int >> 16 == net_C or ip_int >> 22 == net_ISP or ip_int >> 16 == net_DHCP def main(): for ip in ['10.20.0.111', '10.10.42.1', '100.64.228.13', '221.222.222.33', '8.8.8.8', '114.114.144.114', '192.168.31.46']: print("is_internal_ip: ip: %s, \t result: %s" % (ip, is_internal_ip(ip))) # 方法1:掩码对比
运行结果:
is_internal_ip: ip: 10.20.0.111, result: True is_internal_ip: ip: 10.10.42.1, result: True is_internal_ip: ip: 100.64.228.13, result: False is_internal_ip: ip: 221.222.222.33, result: False is_internal_ip: ip: 8.8.8.8, result: False is_internal_ip: ip: 114.114.144.114, result: False is_internal_ip: ip: 192.168.31.46, result: True
其中,map、reduce、lambda 函数的用法示例:
>>> map(int, '12.34'.split('.')) [12, 34] >>> reduce(lambda x,y:(x<<8)+y, [12, 34]) 3106 >>> 12 * 256 + 34 3106 >>> >>> map(int, '192.168.31.46'.split('.')) [192, 168, 31, 46] >>> reduce(lambda x,y:(x<<8)+y, [192, 168, 31, 46]) 3232243502
实现方法二:字符串对比
# 方法2:字符串对比 def is_internal_ip2(ip_str): ip_str2 = '' for item in ip_str.split('.'): if(len(item)) == 1: item = "00" + item if(len(item)) == 2: item = "0" + item ip_str2 = ip_str2 + '.' + item ip_str2 = ip_str2.lstrip('.') inet_A_array = ['010.000.000.000','010.255.255.255'] inet_B_array = ['172.016.000.000','172.031.255.255'] inet_C_array = ['192.168.000.000','192.168.255.255'] inet_ISP_array = ['100.064.000.000','100.127.255.255'] inet_DHCP_array = ['169.254.000.000','169.254.255.255'] # print("ip_int: %s, ip_str2: %s" % (ip_str, ip_str2)) return (ip_str2 >= inet_A_array[0] and ip_str2 < = inet_A_array[1]) or (ip_str2 >= inet_B_array[0] and ip_str2 < = inet_B_array[1]) or (ip_str2 >= inet_C_array[0] and ip_str2 < = inet_C_array[1]) \ or (ip_str2 >= inet_ISP_array[0] and ip_str2 <= inet_ISP_array[1]) or (ip_str2 >= inet_DHCP_array[0] and ip_str2 < = inet_DHCP_array[1]) def main(): for ip in ['10.20.0.111', '10.10.42.1', '100.64.228.13', '221.222.222.33', '8.8.8.8', '114.114.144.114', '192.168.31.46']: print("is_internal_ip: ip: %s, \t result: %s" % (ip, is_internal_ip2(ip))) # 方法2:字符串对比
运行结果:
is_internal_ip: ip: 10.20.0.111, result: True is_internal_ip: ip: 10.10.42.1, result: True is_internal_ip: ip: 100.64.228.13, result: True is_internal_ip: ip: 221.222.222.33, result: False is_internal_ip: ip: 8.8.8.8, result: False is_internal_ip: ip: 114.114.144.114, result: False is_internal_ip: ip: 192.168.31.46, result: True
四、应用实例
Python 实现的完整代码
#!/usr/bin/env python # -*- coding:utf-8 -*- # # Copyright 2015 by mimvp.com ''' 判断ip地址是否内网ip,参考米扑博客 https://blog.mimvp.com/article/30447.html A类地址: 10.0.0.0/8 10.0.0.0--10.255.255.255 B类地址: 172.16.0.0/12 172.16.0.0--172.31.255.255 C类地址: 192.168.0.0/16 192.168.0.0--192.168.255.255 运营商: 100.64.0.0/10 100.64.0.0--100.127.255.255 DHCP: 169.254.0.0/16 169.254.0.0--169.254.255.255 测试ip: '10.50.42.1', '100.64.228.13', '192.168.31.46', '8.8.8.8' 2015-02-05 ''' import sys reload(sys) sys.setdefaultencoding('utf-8') def ip_into_int(ip): # 先把 192.168.31.46 用map分割'.'成数组,然后用reduuce+lambda转成10进制的 3232243502 # (((((192 * 256) + 168) * 256) + 31) * 256) + 46 return reduce(lambda x,y:(x<<8)+y,map(int,ip.split('.'))) # 方法1:掩码对比 def is_internal_ip(ip_str): ip_int = ip_into_int(ip_str) net_A = ip_into_int('10.255.255.255') >> 24 net_B = ip_into_int('172.31.255.255') >> 20 net_C = ip_into_int('192.168.255.255') >> 16 net_ISP = ip_into_int('100.127.255.255') >> 22 net_DHCP = ip_into_int('169.254.255.255') >> 16 return ip_int >> 24 == net_A or ip_int >>20 == net_B or ip_int >> 16 == net_C or ip_int >> 22 == net_ISP or ip_int >> 16 == net_DHCP # 方法2:字符串对比 def is_internal_ip2(ip_str): ip_str2 = '' for item in ip_str.split('.'): if(len(item)) == 1: item = "00" + item if(len(item)) == 2: item = "0" + item ip_str2 = ip_str2 + '.' + item ip_str2 = ip_str2.lstrip('.') inet_A_array = ['010.000.000.000','010.255.255.255'] inet_B_array = ['172.016.000.000','172.031.255.255'] inet_C_array = ['192.168.000.000','192.168.255.255'] inet_ISP_array = ['100.064.000.000','100.127.255.255'] inet_DHCP_array = ['169.254.000.000','169.254.255.255'] # print("ip_int: %s, ip_str2: %s" % (ip_str, ip_str2)) return (ip_str2 >= inet_A_array[0] and ip_str2 < = inet_A_array[1]) or (ip_str2 >= inet_B_array[0] and ip_str2 < = inet_B_array[1]) or (ip_str2 >= inet_C_array[0] and ip_str2 < = inet_C_array[1]) \ or (ip_str2 >= inet_ISP_array[0] and ip_str2 <= inet_ISP_array[1]) or (ip_str2 >= inet_DHCP_array[0] and ip_str2 < = inet_DHCP_array[1]) def main(): for ip in ['10.20.0.111', '10.10.42.1', '100.64.228.13', '221.222.222.33', '8.8.8.8', '114.114.144.114', '192.168.31.46']: print("is_internal_ip: ip: %s, \t result: %s" % (ip, is_internal_ip(ip))) # 方法1:掩码对比 print("is_internal_ip: ip: %s, \t result: %s" % (ip, is_internal_ip2(ip))) # 方法2:字符串对比 if __name__ == '__main__': main() # print(map(int,'192.168.31.46'.split('.'))) # [192, 168, 31, 46] # print(ip_into_int('192.168.31.46')) # 3232243502 # print(100 >> 4) # 6
运行结果:
is_internal_ip: ip: 10.20.0.111, result: True is_internal_ip: ip: 10.20.0.111, result: True is_internal_ip: ip: 10.10.42.1, result: True is_internal_ip: ip: 10.10.42.1, result: True is_internal_ip: ip: 100.64.228.13, result: True is_internal_ip: ip: 100.64.228.13, result: True is_internal_ip: ip: 221.222.222.33, result: False is_internal_ip: ip: 221.222.222.33, result: False is_internal_ip: ip: 8.8.8.8, result: False is_internal_ip: ip: 8.8.8.8, result: False is_internal_ip: ip: 114.114.144.114, result: False is_internal_ip: ip: 114.114.144.114, result: False is_internal_ip: ip: 192.168.31.46, result: True is_internal_ip: ip: 192.168.31.46, result: True
Linux Shell 脚本实现
#!/bin/bash # Copyright 2015 by mimvp.com ## 检测ip是否内网ip, 1-内网ip, 0-非内网ip,用法: result=$(mimvp_is_internal_ip "100.64.228.13") function mimvp_is_internal_ip() { ip_str="$1" ip_str2='' ip_array=(${ip_str//./ }) for item in ${ip_array[@]} do item_length=${#item} # 获取item字符串的长度 if [ "${item_length}" -eq "1" ]; then item="00${item}" fi if [ "${item_length}" -eq "2" ]; then item="0${item}" fi # echo "item: $item item_length: ${item_length}" ip_str2="${ip_str2}.${item}" done ip_str2=${ip_str2:1} # 起始下标0,第2个字段(下标1)截取 # echo "ip_str2: ${ip_str2}" inet_A_array=('010.000.000.000' '010.255.255.255') inet_B_array=('172.016.000.000' '172.031.255.255') inet_C_array=('192.168.000.000' '192.168.255.255') inet_ISP_array=('100.064.000.000' '100.127.255.255') inet_DHCP_array=('169.254.000.000' '169.254.255.255') # echo "${inet_A_array[0]} ${inet_A_array[1]}" # echo "${inet_B_array[0]} ${inet_B_array[1]}" # echo "${inet_C_array[0]} ${inet_C_array[1]}" # echo "${inet_ISP_array[0]} ${inet_ISP_array[1]}" # echo "${inet_DHCP_array[0]} ${inet_DHCP_array[1]}" result=0 if [[ "${ip_str2}" > "${inet_A_array[0]}" && "${ip_str2}" < "${inet_A_array[1]}" ]]; then result=1 fi if [[ "${ip_str2}" > "${inet_B_array[0]}" && "${ip_str2}" < "${inet_B_array[1]}" ]]; then result=1 fi if [[ "${ip_str2}" > "${inet_C_array[0]}" && "${ip_str2}" < "${inet_C_array[1]}" ]]; then result=1 fi if [[ "${ip_str2}" > "${inet_ISP_array[0]}" && "${ip_str2}" < "${inet_ISP_array[1]}" ]]; then result=1 fi if [[ "${ip_str2}" > "${inet_DHCP_array[0]}" && "${ip_str2}" < "${inet_DHCP_array[1]}" ]]; then result=1 fi echo $result } result=$(mimvp_is_internal_ip "100.64.228.13") echo "result: $result" ## 1
参考推荐:
常见路由器的默认网关 IP 是 192.168.1.1 的由来
Nginx 限制单个IP的并发连接数/速度防止恶意攻击/蜘蛛爬虫采集
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2019-07-10 05:46:18
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!