From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!/usr/bin/env perl
use 5.012;
no warnings 'uninitialized';
use Carp;
use Encode;
use YAML;
use Cwd qw'cwd abs_path';
use POSIX qw/strftime/;
#初始化本地时间
my $time = strftime( "%Y%m%d", localtime() );
#获取当前脚本绝对路径
my $dir = dirname( abs_path($0) );
#指定系统路径分隔符
my $split = "/";
#初始化相关变量
my ( $config_dir, $report_dir );
#设置配置文件路径
my $config_ini = $dir . $split . "config.ini";
#------------------------------------------------------------------------------
#机房数据映射哈希
#------------------------------------------------------------------------------
my %location = (
"bbbsuan" => "xxx房",
"bbbboshi" => "xxx机房",
"bbbian" => "xxx房",
"bbbyangmen" => "xxx机房",
"bbb0" => "xxx机房",
"bbbXDS" => "xxx厦",
"bbbCDS" => "xxx厦",
"bbbHXHL" => "xxx鸿联",
"bbbHXDX" => "xxx电信",
"bbbHXLD" => "xxx联通",
);
#------------------------------------------------------------------------------
#初始化配置文件路径
#------------------------------------------------------------------------------
sub create_ini {
#配置文件初始化
my $text = '#配置目录文件夹
config_dir = config
report_dir = report
';
#将配置文件转码未CP936
$text = decode( 'cp936', "$text" );
#判断INI配置文件是否存在
write_file( $config_ini, $text );
}
#------------------------------------------------------------------------------
#防火墙配置解析准备
#------------------------------------------------------------------------------
sub prepare {
#初始化配置文件
create_ini() unless -f $config_ini;
my $config = new Config::Tiny->read($config_ini);
#如果实例化成功则croak
croak "请检查配置文件是否存在" unless $config;
#网络配置文件夹
$config_dir = $dir . $split . $config->{"_"}{"config_dir"};
#报表输出文件夹
$report_dir = $dir . $split . $config->{"_"}{"report_dir"};
#检查相关文件夹是否存在,不存在则新建
mkdir $config_dir unless -d $config_dir;
mkdir $report_dir unless -d $report_dir;
}
#------------------------------------------------------------------------------
#将数据写入EXCEL表格
#------------------------------------------------------------------------------
sub write_excel {
#接收外部传递的配置文件夹
my $rev = shift;
#获取计算结果
my $ret = ip_info($rev);
#网络设备本身IP信息
my $ret1 = $ret->[0];
#接入层交换机MAC信息
my $ret2 = $ret->[1];
#Incomplete ARP MAC信息
my $ret3 = $ret->[2];
#IPPHONE MAC 信息
my $ret4 = $ret->[3];
# 802.1x 认证信息
my $ret5 = $ret->[4];
#异常的ARP MAC信息
my $ret6 = $ret->[5];
#获取解析到的IP并打印
my $ret1_count = scalar( keys %{$ret1} );
my $ret2_count = scalar( keys %{$ret2} );
my $ret3_count = scalar( keys %{$ret3} );
my $ret4_count = scalar( keys %{$ret4} );
my $ret5_count = scalar( keys %{$ret5} );
my $ret6_count = scalar( keys %{$ret6} );
#打印扫描到的IP数量
say "共扫描到 $ret1_count 个网络设备IP";
say "共扫描到 $ret2_count 个服务器IP";
say "共扫描到 $ret3_count 个Incomplete IP";
say "共扫描到 $ret4_count 台IPPHONE_模拟话机";
say "共扫描到 $ret5_count 台 dot1x 认证PC主机";
say "共有 $ret6_count 个解析异常IP \n";
#创建EXCEL表格
my $wb_name = "IP地址归属表" . "_$time" . '.xls';
#设备绝对路径
my $filename = $report_dir . $split . $wb_name;
my $workbook = Spreadsheet::WriteExcel->new($filename);
#新建sheet
my $sheet1 = decode( 'cp936', '网络设备 IP 定位表' );
my $sheet2 = decode( 'cp936', '服务器 IP 定位表' );
my $sheet3 = decode( 'cp936', 'Incomplete ARP定位表' );
my $sheet4 = decode( 'cp936', 'IPPHONE_模拟电话 记录表' );
my $sheet5 = decode( 'cp936', '802.1x 认证PC主机' );
my $sheet6 = decode( 'cp936', '解析异常 ARP 记录表' );
my $worksheet1 = $workbook->add_worksheet($sheet1);
my $worksheet2 = $workbook->add_worksheet($sheet2);
my $worksheet3 = $workbook->add_worksheet($sheet3);
my $worksheet4 = $workbook->add_worksheet($sheet4);
my $worksheet5 = $workbook->add_worksheet($sheet5);
my $worksheet6 = $workbook->add_worksheet($sheet6);
#设置表单格式
my $format = $workbook->add_format();
$format->set_bold();
$format->set_color('purple');
$format->set_bg_color('orange');
$format->set_size(16);
$format->set_border(1);
$format->set_align('center');
$format->set_valign('vcenter');
my $format_1 = $workbook->add_format();
$format_1->set_size(12);
$format_1->set_border(1);
$format_1->set_align('center');
$format_1->set_valign('vcenter');
my $format_2 = $workbook->add_format();
$format_2->set_size(12);
$format_2->set_align('center');
$format_2->set_valign('vcenter');
#设置格式
$worksheet1->set_column( 0, 7, 28.5, $format_2 );
$worksheet2->set_column( 0, 7, 28.5, $format_2 );
$worksheet3->set_column( 0, 7, 28.5, $format_2 );
$worksheet4->set_column( 0, 7, 28.5, $format_2 );
$worksheet5->set_column( 0, 7, 28.5, $format_2 );
$worksheet6->set_column( 0, 7, 28.5, $format_2 );
#创建表单-表头
my $excel_array = [
decode( 'cp936', "IP地址" ),
decode( 'cp936', "关联设备" ),
decode( 'cp936', "关联接口" ),
decode( 'cp936', "MAC地址" ),
decode( 'cp936', "所属VLAN|BD" ),
decode( 'cp936', "上游网关设备" ),
decode( 'cp936', "所属VRF" ),
decode( 'cp936', "所在机房" ),
];
$worksheet1->write_row( 0, 0, $excel_array, $format );
$worksheet2->write_row( 0, 0, $excel_array, $format );
$worksheet3->write_row( 0, 0, $excel_array, $format );
$worksheet4->write_row( 0, 0, $excel_array, $format );
$worksheet5->write_row( 0, 0, $excel_array, $format );
$worksheet6->write_row( 0, 0, $excel_array, $format );
#sheet1写入数据
my $row1 = 1;
foreach my $ip ( sort ( keys %{$ret1} ) ) {
#获取解析结果并分
my $ip_info = $ret1->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet1->set_row( $row1, 22.5 );
$worksheet1->write_row( $row1, 0, $array, $format_1 );
$row1++;
}
#sheet2写入数据
my $row2 = 1;
foreach my $ip ( sort ( keys %{$ret2} ) ) {
#获取解析结果并分解
my $ip_info = $ret2->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet2->set_row( $row2, 22.5 );
$worksheet2->write_row( $row2, 0, $array, $format_1 );
$row2++;
}
#sheet3写入数据
my $row3 = 1;
foreach my $ip ( sort ( keys %{$ret3} ) ) {
#获取解析结果并分解
my $ip_info = $ret3->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet3->set_row( $row3, 22.5 );
$worksheet3->write_row( $row3, 0, $array, $format_1 );
$row3++;
}
#sheet4写入数据
my $row4 = 1;
foreach my $ip ( sort ( keys %{$ret4} ) ) {
#获取解析结果并分解
my $ip_info = $ret4->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet4->set_row( $row4, 22.5 );
$worksheet4->write_row( $row4, 0, $array, $format_1 );
$row4++;
}
#sheet+5写入数据
my $row5 = 1;
foreach my $ip ( sort ( keys %{$ret5} ) ) {
#获取解析结果并分解
my $ip_info = $ret5->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet5->set_row( $row5, 22.5 );
$worksheet5->write_row( $row5, 0, $array, $format_1 );
$row5++;
}
#sheet+6写入数据
my $row6 = 1;
foreach my $ip ( sort ( keys %{$ret6} ) ) {
#获取解析结果并分解
my $ip_info = $ret6->{$ip};
my $ipaddr = $ip;
my $hostname = $ip_info->{"hostname"};
my $interface = $ip_info->{"interface"};
my $mac = $ip_info->{"mac"};
my $vlan = $ip_info->{"vlan"};
my $dc_code = $ip_info->{"location"};
my $vrf = $ip_info->{"vpn_instance"};
my $gateway = $ip_info->{"gate_device"};
#转换机房数据字典
my $location;
if ( exists $location{$dc_code} ) {
$location = $location{$dc_code};
$location = decode( 'cp936', $location );
}
else {
$location = decode( 'cp936', "非标命名未解析成功" );
}
#临时封装匿名数组
my $array =
[ $ipaddr, $hostname, $interface, $mac, $vlan, $gateway, $vrf, $location ];
#写入计算数据
$worksheet6->set_row( $row6, 22.5 );
$worksheet6->write_row( $row6, 0, $array, $format_1 );
$row6++;
}
#持久化数据结构
my $yaml = "IP归属查询.yaml";
$yaml = $report_dir . $split . $yaml;
YAML::DumpFile( $yaml, $ret );
}
#------------------------------------------------------------------------------
#实际处理函数
#------------------------------------------------------------------------------
say "-" x 100 . "\n";
say 'IP地址扫描工具V0.6 BY<careline@126.com>' . "\n";
prepare();
say "-" x 100 . "\n";
write_excel($config_dir);
say "-" x 100 . "\n";