sqlserver 根据IP和数量,计算应该使用的掩码IP地址段

sqlserver 根据IP和数量,计算应该使用的掩码IP地址段

起因

最近在采集各个IP段的来源,然后,根据来源相同的IP,合并成一个大IP段,用来制作一个IP禁止或同行的策略。

CSDN 文盲老顾的博客https://blog.csdn.net/superwfei

老顾的个人社区https://bbs.csdn.net/forums/bfba6c5031e64c13aa7c60eebe858a5f?category=10003&typeId=3364713

但是,在合并了相同来源,并计算相同来源之后的 IP 段之后,出现了一点点小麻烦,需要人工去计算对应的掩码,来简化IP策略。

比如:1.0.1.0这个IP段,来源相同的有768个IP,即:1.0.1.0-1.0.3.255。那么,对应的掩码应该是 1.0.1.0/24 和 1.0.2.0/23 两个掩码地址段。

但是人工计算就太麻烦了,所以,使用 sqlserver 来进行了一下计算。

数据来源

使用采集方式,可以从百度获得IP的来源,以老顾获取的数据为例:

text 复制代码
1.0.0.0         16777216   美国                                   Cloudflare            IDC
1.0.1.0         16777472   中国           福建省          福州市        未知                    未知
1.0.2.0         16777728   中国           福建省          福州市        未知                    未知
1.0.3.0         16777984   中国           福建省          福州市        未知                    未知
1.0.4.0         16778240   澳大利亚         维多利亚州        墨尔本        Gtelecom P            机构专线
1.0.5.0         16778496   澳大利亚         维多利亚州        墨尔本        Gtelecom P            机构专线
1.0.6.0         16778752   澳大利亚         维多利亚州        墨尔本        Gtelecom P            机构专线
1.0.7.0         16779008   澳大利亚         维多利亚州        墨尔本        Gtelecom P            机构专线
1.0.8.0         16779264   中国           广东省          广州市        未知                    未知
1.0.9.0         16779520   中国           广东省          广州市        未知                    未知
1.0.10.0        16779776   中国           广东省          广州市        未知                    未知
1.0.11.0        16780032   中国           广东省          广州市        未知                    未知
1.0.12.0        16780288   中国           广东省          广州市        未知                    未知
1.0.13.0        16780544   中国           广东省          广州市        未知                    未知
1.0.14.0        16780800   中国           广东省          广州市        未知                    未知
1.0.15.0        16781056   中国           广东省          广州市        未知                    未知
1.0.16.0        16781312   日本           东京都          东京         works                 机构专线
1.0.17.0        16781568   日本                                   未知                    机构专线
1.0.18.0        16781824   日本                                   未知                    机构专线
1.0.19.0        16782080   日本                                   未知                    机构专线
1.0.20.0        16782336   日本                                   未知                    机构专线
1.0.21.0        16782592   日本                                   未知                    机构专线
1.0.22.0        16782848   日本                                   未知                    机构专线
1.0.23.0        16783104   日本                                   未知                    机构专线
1.0.24.0        16783360   日本                                   未知                    机构专线
1.0.25.0        16783616   日本                                   未知                    机构专线
1.0.26.0        16783872   日本                                   未知                    机构专线
1.0.27.0        16784128   日本                                   未知                    机构专线
1.0.28.0        16784384   日本                                   未知                    机构专线
1.0.29.0        16784640   日本                                   未知                    机构专线
1.0.30.0        16784896   日本                                   未知                    机构专线
1.0.31.0        16785152   日本                                   未知                    机构专线

将采集的结果导入到sqlserver 后,可以对连续的相同IP用途、来源进行合并

数据合并

sql 复制代码
;with t as (
	select *
		,(case 
			when ISP in ('亚马逊','微软公司','美国礼来公司','阿里云','华为','腾讯','甲骨文软件系统有限公司','OCULUS NETWORKS INC','Partner Communications') then ISP
			when 企业<>'' then 国 + ' ' + 企业
			when 国<>'中国' and ISP<>'未知' then 国 + ' ' + ISP
			--when 国='中国' and 用途<>'未知' then master.dbo.regexreplace(省,'[省市]','') + master.dbo.regexreplace(市,'[省市]','') + ' ' + 用途
			when 国='中国' then
				(
				case when 省='' and isp<>'未知' and 用途<>'未知' then isp + ' ' + 用途
				when 省<>'' then master.dbo.regexreplace(省,'([省市]|((回族)?自治|特别行政|)[区州])','') + master.dbo.regexreplace(市,'([省市]|布依族苗族自治州|苗族侗族自治州)','') + ' ' + 用途
				else
				国 + ' ' + 用途 end
				)
			else 国 + ' ' + 用途 end
		) txt
		,row_number() over(order by ip_l) rid 
	from IP数据表
	--where ip_l <16778240 
) 
select *
into #t1
from (
	select *,0 nid from t where rid=1
	union
	select * ,row_number() over(order by a.rid) nid 
	from t a
	where exists(select top 1 1 from t where rid=a.rid-1 and txt<>a.txt)
	union
	select '',min(ip_l) + 65536 * 256,'','','','','','','',99999,count(0) + 1 
	from t a
	where exists(select top 1 1 from t where rid=a.rid-1 and txt<>a.txt)
) a
order by ip_l

在这里,我以数据第一行和最后一行对数据进行了一下补充,避免无法计算IP数量。

其中用途的计算是根据老顾个人的习惯来的,可自行调整,然后将结果存放到临时表 t1 中

计算连续IP数量

sql 复制代码
select a.ip_l,a.ip,a.txt,(b.ip_l-a.ip_l) nums
into #t2
from #t1 a 
left join #t1 b on a.nid+1=b.nid
where b.ip is not null

得到的数据如下:

html 复制代码
16777216             1.0.0.0         美国 Cloudflare, Inc   256
16777472             1.0.1.0         福建福州 未知              768
16778240             1.0.4.0         澳大利亚 Gtelecom Pty Lt 1024
16779264             1.0.8.0         广东广州 未知              2048
16781312             1.0.16.0        日本 works             256
16781568             1.0.17.0        日本 机构专线              3840
16785408             1.0.32.0        广东广州 IDC             256
16785664             1.0.33.0        广东广州 未知              7680
16793344             1.0.63.0        广东广州 IDC             256
16793600             1.0.64.0        日本 Enecom.Inc.       16384
16809984             1.0.128.0       泰国 TOT Public Compan 17664
16827648             1.0.197.0       泰国 Ministry of Educa 256
16827904             1.0.198.0       泰国 TOT Public Compan 14848

对连续的IP进行数量计算,并将结果保存到临时表 t2 中。

其中第一列的整形为 bigint 类型,与第二列的字符串 IP 是可以互相转换的,为了方便,先将对应函数贴出来。

使用自定义函数,转换IPv4 与 bigint 类型

sql 复制代码
CREATE FUNCTION [dbo].[fn_BigIntToIPv4]
(
	@num bigint
)
RETURNS varchar(15)
AS
BEGIN
	DECLARE @result varchar(15)
	
	--select @result = master.dbo.fn_varbintohexstr(@num)
	SELECT @result = (
		select stuff((
			select '.'+convert(varchar(3),convert(int,substring(master.dbo.fn_cdc_hexstrtobin('0x'+match),1,1))) 
			from master.dbo.regexmatches(substring(master.dbo.fn_varbintohexstr(convert(bigint,@num)),11,18),'[\s\S]{2}') 
			for xml path('')
		),1,1,''))

	RETURN @result

END


CREATE FUNCTION [dbo].[fn_IPv4ToBigInt]
(
	@ip varchar(15)
)
RETURNS bigint
AS
BEGIN
	DECLARE @result bigint

	select @result = (select convert(bigint,substring(master.dbo.fn_cdc_hexstrtobin('0x'+(
			select 
				substring(master.dbo.fn_varbintohexstr(convert(int,match)),9,10)
			from master.dbo.regexmatches(@ip,'\d+')
			for xml path('')
		)),1,4)))

	RETURN @result

END

关于 regex 相关的函数,可以参考正则表达式使模式匹配和数据提取变得更容易(David Banister)一文的内容。

根据 起始 IP 地址和连续 IP 数量,进行掩码计算

sql 复制代码
CREATE FUNCTION [dbo].[IPmask]
(	
	@ip varchar(20),@nums bigint
)
RETURNS TABLE 
AS
RETURN 
(
	with t1 as (
		select master.dbo.fn_IPv4ToBigInt(@ip) l,@nums n,@nums s,0 t 
		union all
		select l / 2,n / 2,s,t + 1 
		from t1
		where l % 2 = 0 and n > 0 and s >= power(2,t + 1)
		union all
		select (l + 1) * power(2,t),s - power(2,t),s - power(2,t),0
		from t1
		where s > 0 and (s < power(2,t + 1) or l % 2 = 1)
	),t2 as (
		select *,row_number() over(partition by s order by n) rid
		from t1 
		where s > 0
	)
	select master.dbo.fn_biginttoIPv4(l * power(2,t)) + '/' + convert(varchar,32 - t) v,row_number() over(order by s desc) nid
	from t2 
	where rid=1
)

创建一个表值函数,用来生成应该使用的 IP 掩码地址段。

在这里使用了 CTE 递归,但是,有很大概率,会出现递归超过100层的情况,所以,我们需要在使用的时候,追加上 OPTION (MAXRECURSION 0) 参数。

需要注意的是,在函数内,是无法使用该参数的,只能在调用该表值函数的查询指令中使用该指令。

同时,为了能保证生成出来的地址掩码是连续的,且从小到大排列,所以追加了开窗排序函数的使用。

最终计算

sql 复制代码
select convert(varchar(15),ip) ip,ip_l,nums,v,convert(nvarchar(20),txt) txt,nid
from #t2
cross apply master.dbo.IPmask(ip,nums)
where ip_l<=master.dbo.fn_ipv4tobigint('1.0.255.0')
order by ip_l,nid
OPTION (MAXRECURSION 0)

使用 apply ,将初始IP和IP数量作为参数传递给刚才我们创建的函数,就可以得到对应的 IP 掩码结果了。

html 复制代码
ip              ip_l                 nums                 v                                              txt                  nid
--------------- -------------------- -------------------- ---------------------------------------------- -------------------- --------------------
1.0.0.0         16777216             256                  1.0.0.0/24                                     美国 Cloudflare, Inc   1
1.0.1.0         16777472             768                  1.0.1.0/24                                     福建福州 未知              1
1.0.1.0         16777472             768                  1.0.2.0/23                                     福建福州 未知              2
1.0.4.0         16778240             1024                 1.0.4.0/22                                     澳大利亚 Gtelecom Pty Lt 1
1.0.8.0         16779264             2048                 1.0.8.0/21                                     广东广州 未知              1
1.0.16.0        16781312             256                  1.0.16.0/24                                    日本 works             1
1.0.17.0        16781568             3840                 1.0.17.0/24                                    日本 机构专线              1
1.0.17.0        16781568             3840                 1.0.18.0/23                                    日本 机构专线              2
1.0.17.0        16781568             3840                 1.0.20.0/22                                    日本 机构专线              3
1.0.17.0        16781568             3840                 1.0.24.0/21                                    日本 机构专线              4
1.0.32.0        16785408             256                  1.0.32.0/24                                    广东广州 IDC             1
1.0.33.0        16785664             7680                 1.0.33.0/24                                    广东广州 未知              1
1.0.33.0        16785664             7680                 1.0.34.0/23                                    广东广州 未知              2
1.0.33.0        16785664             7680                 1.0.36.0/22                                    广东广州 未知              3
1.0.33.0        16785664             7680                 1.0.40.0/21                                    广东广州 未知              4
1.0.33.0        16785664             7680                 1.0.48.0/21                                    广东广州 未知              5
1.0.33.0        16785664             7680                 1.0.56.0/22                                    广东广州 未知              6
1.0.33.0        16785664             7680                 1.0.60.0/23                                    广东广州 未知              7
1.0.33.0        16785664             7680                 1.0.62.0/24                                    广东广州 未知              8
1.0.63.0        16793344             256                  1.0.63.0/24                                    广东广州 IDC             1
1.0.64.0        16793600             16384                1.0.64.0/18                                    日本 Enecom.Inc.       1
1.0.128.0       16809984             17664                1.0.128.0/18                                   泰国 TOT Public Compan 1
1.0.128.0       16809984             17664                1.0.192.0/22                                   泰国 TOT Public Compan 2
1.0.128.0       16809984             17664                1.0.196.0/24                                   泰国 TOT Public Compan 3
1.0.197.0       16827648             256                  1.0.197.0/24                                   泰国 Ministry of Educa 1
1.0.198.0       16827904             14848                1.0.198.0/23                                   泰国 TOT Public Compan 1
1.0.198.0       16827904             14848                1.0.200.0/21                                   泰国 TOT Public Compan 2
1.0.198.0       16827904             14848                1.0.208.0/20                                   泰国 TOT Public Compan 3
1.0.198.0       16827904             14848                1.0.224.0/19                                   泰国 TOT Public Compan 4

后记

这个函数目前是第一版,其实稍微有点不太好用,主要的方面就是,一个大的连续IP段中,出现个别其他用途的IP时,老顾暂时没想到怎么合并大的IP段,并将其中个别IP段标记为异常。

比如刚才的结果中,1.0.128.0-1.0.255.255 最理想的掩码表示,应该是 1.0.128.0/17 用途 泰国 TOT Public Compan,其中 1.0.197.0/24 为异常数据,用途为 泰国 Ministry of Educa。这样就只需要两个 IP 掩码段就能表述清楚了。

PS:这个函数也就是临时写出来的,如果有错误,还请进行指正。

相关推荐
czhc11400756633 天前
6.11:halcon,Sqlserver;项目sql连接;git
git·sql·sqlserver
不剪发的Tony老师3 天前
SQLQueryStress:一款SQL Server查询压力测试工具
数据库·sqlserver·压力测试
xuefuhe4 天前
SQL Server变量复用陷阱
sqlserver
刚子编程6 天前
EF Core 8 + SQL Server:Contains() 突然报 “关键字 WITH 附近有语法错误“?一篇避坑指南
cte·ef core 8·contains 查询·sql server 语法错误·重大变更
星光不负赶路人!6 天前
【工作记录】sqlserver数据库操作及迁移
服务器·数据库·sqlserver
码上有光6 天前
c++:二叉搜索树(map和set的底层结构)
开发语言·c++·递归·二叉搜索树
CSharp精选营6 天前
EF Core 8 + SQL Server:Contains() 突然报 "关键字 WITH 附近有语法错误"?一篇避坑指南
cte·ef core 8·contains 查询·sql server 语法错误·重大变更
_1_78 天前
SQL Server 磁盘满了 收缩日志
数据库·sqlserver
满昕欢喜8 天前
第2章 SQL Server 2019服务器管理
数据库·sqlserver