问题
安全团队会使用IP地址进行漏洞扫描,由于IP众多,需要根据漏洞类型来分配相应的责任人。由于识别IP的owner是根据服务器的资产信息来确认,有些IP比如虚拟IP无法匹配。 因此会维护一个类似IP和责任人的表格。但是由于目前的实现是根据精确的IP地址匹配,导致维护工作量比较大。所以考虑使用子网来匹配这些IP。
实现
主要是两个主要功能。
第一个是根据IP和子网来判断IP是否属于该子网。由于PowerQuery本身没有提供IP的相关函数,所以只能自定义。 第二个功能就是根据IP子网信息来返回owner。参数为需要匹配的IP和一个包含IP或者子网以及owner的表。
第一个表为vulnerability。关键字段如下
| IP | PluginID | Output | Solution | Found |
|---|---|---|---|---|
| 192.168.10.1 | 11111 | glib<1.0 | Upgrade to 1.0 | 2025-7-8 10:00 |
| 192.168.20.2 | 11111 | glib<1.0 | Upgrade to 1.0 | 2025-7-8 10:00 |
| 192.168.30.1 | 11111 | glib<1.0 | Upgrade to 1.0 | 2025-7-8 10:00 |
第二个表为override, 关键字段如下
| IP | Owner |
|---|---|
| 192.168.10.0/24 | Tom |
| 192.168.20.2 | Jerry |
let
Owner = (ipAddress as text, subnetTable as table) as text =>
let
// Function to check if IP is in a single subnet
IsIPInSubnet = (ip as text, subnet as text) as logical =>
let
// Normalize subnet to CIDR format if it's a plain IP address
normalizedSubnet =
if Text.Contains(subnet, "/") then
subnet
else
subnet & "/32",
// Split subnet into network address and CIDR
subnetParts = Text.Split(normalizedSubnet, "/"),
networkAddress = subnetParts{0},
cidrMask = Number.From(subnetParts{1}),
// Convert IP to integer
IPToInteger = (ip as text) as number =>
let
parts = Text.Split(ip, "."),
part1 = Number.From(parts{0}) * 256 * 256 * 256,
part2 = Number.From(parts{1}) * 256 * 256,
part3 = Number.From(parts{2}) * 256,
part4 = Number.From(parts{3})
in
part1 + part2 + part3 + part4,
// Convert IP to binary mask
SubnetMask = (cidr as number) as number =>
let
mask = Number.Power(2, 32) - Number.Power(2, 32 - cidr)
in
mask,
// Get network portion
ipInt = IPToInteger(ip),
networkInt = IPToInteger(networkAddress),
mask = SubnetMask(cidrMask)
in
Number.BitwiseAnd(ipInt, mask) = Number.BitwiseAnd(networkInt, mask),
// Filter table to find matching subnets
matchingRows = Table.SelectRows(subnetTable, each IsIPInSubnet(ipAddress, [IP])),
// Return owner if a match is found, otherwise return empty text
result =
if Table.RowCount(matchingRows) > 0 then
matchingRows[Owner]{0}
else
""
in
result
in
Owner