#包名:HWNET 功能:对华为交换机和路由器进行自动维护的包 引用方法:use HWNET; # package HWNET; use strict; use Data::Dump qw(dump); use Net::Telnet; use POSIX qw(strftime); use Net::Ping; # # 用于测试的子程序 # sub test{ #读取子程序参数 my $this = shift; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; $telnet->put("\n"); #my ($prematch, $match) = $telnet->waitfor("/$prompt/"); print $telnet->lastline; return ; } # # 功能:支持的设备型号列表 # # 列表项示例: # S8016' => 'Quidway S8016 Routing Switch' # ^ # 设备型号 'disp ver'命令输出结果中标志设备型号的特征字符串 # # 说明: 如果需要支持新的设备型号支持,需要在此列表中增加相应的条目 # my %device_type_list =( 'S8016' => 'Quidway S8016 Routing Switch', 'NE05' => 'Quidway NetEngine 05', 'NE40-8' => 'Quidway NetEngine 40-8 Universal Switching Router', 'NE16' => 'Quidway NetEngine 16E', 'AR46-40' => 'Quidway AR46-40', 'S3050' => 'Quidway S3050C', 'S2026' => 'Quidway S2026', 'S2403H-EI' => 'Quidway S2403H-EI', 'S3526E' => 'Quidway S3526E', 'S2008-EI' => 'Quidway S2008-EI', 'S3050C' => 'Quidway S3050C', ); # 返回程序包支持的设备型号列表 sub supported_device_type_list{ return keys %device_type_list; } # # HWNET对象的构造器 # sub new{ my $class = shift; my $this = { 'STATE'=>'UNCONNECTED', 'INPUT_LOG'=>'in.txt', 'OUTPUT_LOG'=>'out.txt', 'TIMEOUT'=>5, 'PROMPT'=>'' }; return bless $this, $class; } # #登录到网络设备的用户视图 # sub reset{ my $this = shift; # 关闭telnet对象 my $telnet = $this->{'TELNET_OBJECT'}; $telnet->close() if $telnet; # 将各对象各属性复位到初始值 $this = { 'STATE' => 'UNCONNECTED', 'INPUT_LOG' => 'input_log.txt', 'OUTPUT_LOG' => 'output_log.txt', 'TIMEOUT' => 5, 'PROMPT' => '' }; } sub login{ #读取子程序参数 my ($this, $host,$username, $password,$su_password) = @_; my $prompt = $this->{'PROMPT'}; $prompt = '(?:<.+?>|\[.+?\])$' if !$prompt; my $ret=undef; #设置子程序默认返回值 # 验证子程序执行的前提条件 return $ret if $this->{'STATE'} ne 'UNCONNECTED'; my $input_log = $this->{'INPUT_LOG'}; my $output_log = $this->{'OUTPUT_LOG'}; my $timeout = $this->{'TIMEOUT'}; my $telnet = Net::Telnet->new( Timeout=>$timeout, Prompt=>"/$prompt/", Input_log=>$input_log, Output_log=>$output_log, Errmode=>'return' ); #如果建立telnet对象失败,返回 return $ret unless $telnet; $this->{'STATE'}='CONNECTED'; #设置HWNET对象状态 #登录到普通用户模式 return $ret unless $telnet->open($host); my (undef, $match) = $telnet->waitfor('/Password:|Username:/'); if($match eq 'Username:'){ return $ret unless $telnet->put($username."\n"); return $ret unless $telnet->waitfor("/Password:/"); } return $ret unless $telnet->put($password."\n"); return $ret unless $telnet->waitfor("/$prompt/"); $this->{'STATE'} = 'USERMODE'; #保存登录参数给后续操作使用 $this->{'TELNET_OBJECT'} = $telnet; $this->{'USERNAME'} = $username; $this->{'PASSWORD'} = $password; $this->{'SU_PASSWORD'} = $su_password; $this->{'PROMPT'} = $prompt; $ret = 1; return $ret; } # #退出登录 # sub logout{ my $this = shift; my $state = $this->{'STATE'}; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; # 根据TELNET_OBJECT对象所处的不同状态进行不同的操作 $_ = $state; SWITCH: { /^UNCONNECTED$/ && do { last SWITCH; }; /^CONNECTED$/ && do { last SWITCH; }; /^USERMODE$/ && do { $telnet->put("quit\n"); $telnet->waitfor("/$prompt/"); last SWITCH; }; /^SUPERMODE$/ && do { $this->super; $telnet->put("quit\n"); $telnet->waitfor("/$prompt/"); last SWITCH; }; } $this->{'STATE'} = 'UNCONNECTED'; $telnet->close if $telnet; $telnet = undef; return 1; } # #进入super模式 # sub super{ #读取子程序参数 my $this = shift; my $telnet = $this->{'TELNET_OBJECT'}; return undef unless $telnet; my $su_password = $this->{'SU_PASSWORD'}; my $prompt = $this->{'PROMPT'}; my $state = $this->{'STATE'}; my $ret = undef; my $myret = undef; if($state eq 'USERMODE'){ #进入超级用户模式 $myret = $telnet->put("super\n"); goto out unless $myret; my (undef, $match) = $telnet->waitfor("/ Password:|$prompt/i"); goto out if !defined($match); if($match =~ /Password:/){ goto out unless $telnet->put($su_password."\n"); goto out unless $telnet->waitfor("/$prompt/"); } $this->{'STATE'} = 'SUPERMODE'; my $ret = 1; } out: return $ret; } # #获取设备sysname # sub get_sysname{ #读取子程序参数 my $this = shift; my $ret = undef; my $in=""; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; my $state = $this->{'STATE'}; #进入super模式 $this->super; # TODO: 此处需要进行错误处理 #读取设备版本信息 $telnet->put("disp current-config\n"); #处理disp current-config的多页显示情况 my ($prematch, $match); do{{ ($prematch, $match) = $telnet->waitfor("/--- More ---|$prompt/"); $in .= $prematch; if($match =~ /--- More ---/){ $telnet->put(" "); } }}while $match =~ /--- More ---/; $in =~ /sysname (.+)\n/; $ret = $1; return $ret; } # #获取设备型号 # sub get_device_type{ #读取子程序参数 my $this = shift; my $ret = undef; my $in=""; my $telnet = $this->{'TELNET_OBJECT'}; my $su_password = $this->{'SU_PASSWORD'}; my $prompt = $this->{'PROMPT'}; my $state = $this->{'STATE'}; $this->super; #读取设备版本信息 $telnet->put("disp version\n"); #处理disp ver的多页显示情况 my ($prematch, $match); do{{ ($prematch, $match) = $telnet->waitfor("/--- More ---|$prompt/"); $in .= $prematch; if($match =~ /--- More ---/){ $telnet->put(" "); } }}while $match =~ /--- More ---/; #根据设备特征串匹配设备类型 study $in; for(keys %device_type_list){ $ret = $_, last if $in =~ /$device_type_list{$_}/; } return $ret; } # # TODO: 增加对于错误处理的可靠性 # sub backup_config{ #读取参数 my $this = shift; #读取ftp服务器的参数 my ($ftp_server, $ftp_user, $ftp_password) = @_; my $p = Net::Ping->new('tcp', 5); return 0 if ! $p->ping($ftp_server); # 如果ftp服务器无法ping通则返回 #设置telnet参数 my $telnet = $this->{'TELNET_OBJECT'}; my $su_password = $this->{'SU_PASSWORD'}; my $prompt = $this->{'PROMPT'}; # 判断系统的类型 my $sys_name = $this->get_sysname; my $sys_type = $this->get_device_type; print STDERR $sys_type, "\n"; #根据系统类型的不同执行不同的配置备份过程 $_ = $sys_type; SWITCH: { // && do { # 统一的过程 #0. 进入特权用户模式 $this->super; #1. 确定配置文件名(要根据不同的设备型号来确定) my ($pre, $match, $ret); my $config_name = 'config.cfg'; CONFIG_TYPE:{ /^NE05$/ && do{ $telnet->put("disp startup\n"); my ($prematch,undef) = $telnet->waitfor("/$prompt/"); $prematch =~ /Next startup saved-configuration file:\s+(.+)$/m; $telnet->buffer_empty; $config_name = $1; last CONFIG_TYPE; }; /^S8016$/ && do{ $config_name = 'vrpcfg.zip'; last CONFIG_TYPE; }; /^NE40-8$/ && do{ #$telnet->put("disp startup\n"); my #($prematch,undef) = #$telnet->waitfor("/$prompt/"); $prematch =~ #/Next startup saved-configuration #file:\s+(.+)$/m; $telnet->buffer_empty; $config_name = 'vrpcfg.zip'; last CONFIG_TYPE; }; /^NE16$/ && do{ $telnet->put("disp startup\n"); my ($prematch,undef) = $telnet->waitfor("/$prompt/"); $prematch =~ /Next startup saved-configuration file:\s+(.+)$/m; $telnet->buffer_empty; $config_name = $1; last CONFIG_TYPE; }; /^AR46-40$/ && do{ $telnet->put("disp startup\n"); my ($prematch,undef) = $telnet->waitfor("/$prompt/"); $prematch =~ /Next startup saved-configuration file:\s+(.+)$/m; $telnet->buffer_empty; $config_name = $1; last CONFIG_TYPE; }; /^S3050$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; /^S3050C$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; /^S3526E$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; /^S2026$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; /^S2403H-EI$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; /^S2008-EI$/ && do{ $config_name = 'vrpcfg.txt'; last CONFIG_TYPE; }; } # 检查配置文件名 return 0 if $config_name eq ''; #2. 登录ftp服务器 # 延迟 sleep 2; # $telnet->put("ftp $ftp_server\n"); ($pre, $match) = $telnet->waitfor('/User\(.*\)/'); return 0 if !$match or $match !~ /User\(.*\)/; $telnet->put("$ftp_user\n"); $telnet->waitfor('/Password:$/'); $telnet->put("$ftp_password\n"); $telnet->waitfor('/\[ftp\]$/'); #3. 设置为二进制方式 $telnet->put("bin\n"); $telnet->waitfor('/\[ftp\]$/'); #4. 创建存放配置文件的目录 $telnet->put("mkdir netconfig\n"); $telnet->waitfor('/\[ftp\]$/'); #5. 进入目录 $telnet->put("cd netconfig\n"); $telnet->waitfor('/\[ftp\]$/'); #6. 生成备份目录名 my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); $year += 1900; $mon += 1; my $dir_name = "$year-$mon-${mday}_$sys_name"; $telnet->put("mkdir $dir_name\n"); $telnet->waitfor('/\[ftp\]$/'); #7. 进入备份目录 $telnet->put("cd $dir_name\n"); $telnet->waitfor('/\[ftp\]$/'); #8. 上传备份文件 $telnet->put("put $config_name\n"); ($pre, undef) = $telnet->waitfor('/\[ftp\]$/'); return 0 if $pre !~ /200 PORT Command successful\./; #退出ftp $telnet->put("quit\n"); $telnet->waitfor("/$prompt/"); last SWITCH; }; # /^$/ && do { # last SWITCH; # }; } return 1; } # # 功能:将当前登录的vty终端设置为不暂停状态 # sub set_vty_no_pause{ #读取子程序参数 my $this = shift; my $ret = undef; my $in=""; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; my $state = $this->{'STATE'}; my $tmp_type = $this->get_device_type; $this->super; #获取当前用户的虚拟终端号 $telnet->put("disp users\n"); #处理disp users的多页显示情况 my ($prematch, $match); do{{ ($prematch, $match) = $telnet->waitfor("/--- More ---|$prompt/"); $in .= $prematch; if($match =~ /--- More ---/){ $telnet->put(" "); } }}while $match =~ /--- More ---/; $_ = $tmp_type; SWITCH: { do { # 生成命令行 $in =~ /[\+|\*]\s+\d+\s+VTY\s+(\d+)\s+\d\d:\d\d:\d\d\s/; my $ui = $1; my $cmd = "user-interface vty $ui"; if(! $this->sys){ $telnet->put("system\n"); $telnet->waitfor("/$prompt/"); } $telnet->put("$cmd\n"); $telnet->waitfor("/$prompt/"); $telnet->put("screen-length 0\n"); $telnet->waitfor("/$prompt/"); $telnet->put("quit\n"); $telnet->waitfor("/$prompt/"); $telnet->put("return\n"); $telnet->waitfor("/$prompt/"); last SWITCH; } } $ret = 1; return $ret; } # # 功能:将当前登录的vty终端设置为可暂停状态 # sub set_vty_pause{ #读取子程序参数 my $this = shift; my $ret = undef; my $in=""; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; my $state = $this->{'STATE'}; my $tmp_type = $this->get_device_type; $this->super; #获取当前用户的虚拟终端号 $telnet->put("disp users\n"); #处理disp users的多页显示情况 my ($prematch, $match); do{{ ($prematch, $match) = $telnet->waitfor("/--- More ---|$prompt/"); $in .= $prematch; if($match =~ /--- More ---/){ $telnet->put(" "); } }}while $match =~ /--- More ---/; $_ = $tmp_type; SWITCH: { do { # 生成命令行 $in =~ /[\+|\*]\s+\d+\s+VTY\s+(\d+)\s+\d\d:\d\d:\d\d\s/; my $ui = $1; my $cmd = "user-interface vty $ui"; if(! $this->sys){ $telnet->put("system\n"); $telnet->waitfor("/$prompt/"); } $telnet->put("$cmd\n"); $telnet->waitfor("/$prompt/"); $telnet->put("undo screen-length\n"); $telnet->waitfor("/$prompt/"); $telnet->put("quit\n"); $telnet->waitfor("/$prompt/"); $telnet->put("return\n"); $telnet->waitfor("/$prompt/"); last SWITCH; } } $ret = 1; return $ret; } # # 功能:判断系统是否处理在system-view视图,是则返回1,否则返回0。 # sub sys{ #读取子程序参数 my $this = shift; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; $telnet->put("\n"); my ($prematch, $match) = $telnet->waitfor("/$prompt/"); return 1 if $match =~ /\]$/; return 0 if $match =~ />$/; return 0; } sub send_ctrl_k{ my $this = shift; my $telnet = $this->{'TELNET_OBJECT'}; my $prompt = $this->{'PROMPT'}; $telnet->put("\cK"); my ($prematch, $match) = $telnet->waitfor("/$prompt/"); return 1; } sub change_password{ } # #执行指定的命令 # sub exec_cmd{ my $this = shift; my $cmd = shift; my $telnet = $this->{'TELNET_OBJECT'}; $telnet->cmd($cmd); } 1;