linux 巡检脚本,服务巡查,安全检查,通用备份

linux巡检脚本,系统基本信息巡查,系统安全配置巡查,系统服务巡查,通用压缩备份,中间件版本巡查等。

0readme

#服务器巡检脚本
##功能简介
巡检linux服务器相关信息并发送邮件通知
##主要功能
1.服务基本信息检查
检查cpu,磁盘,内存,网络等信息
2.服务应用信息检查
检查各中间件版本信息
3.服务安全校验检查
检查linux系统各项安全配置
4.服务器日志备份灵活配置
配置日志通用备份及应用灵活备份
##配置区域
check.sh 开头配置区域
##启动方式:
#检查所有信息及发送邮件
sh sendMail.sh
#检查所有信息不发送邮件
sh inspection_check_tool.sh
#检查安全信息
sh check.sh

1.inspection_check_tool.sh 基本信息检查脚本

#!/bin/bash

date=date +%Y%m%d;
time=date +%H%M%S;
CHECK_ERROR_LOG=“./log/KaTeX parse error: Expected group after '_' at position 7: {date}_̲{time}_check.log”
if [ -n “$1” ]; then
CHECK_ERROR_LOG=“ 1 " f i p h y c p u = 1" fi phy_cpu= 1"fiphycpu=(cat /proc/cpuinfo | grep “physical id”|sort | uniq | wc -l);
logic_cpu_num= ( c a t / p r o c / c p u i n f o ∣ g r e p " p r o c e s s o r " ∣ w c − l ) ; c p u c o r e n u m = (cat /proc/cpuinfo | grep "processor"| wc -l); cpu_core_num= (cat/proc/cpuinfogrep"processor"∣wcl);cpucorenum=(cat /proc/cpuinfo | grep “cores”|uniq|awk -F: '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲'); cpu_freq=(cat /proc/cpuinfo | grep MHz | uniq | awk -F: '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲'); system_core…(uname -r);
system_version= ( c a t / e t c / o s − r e l e a s e ) ; s y s t e m h o s t n a m e = (cat /etc/os-release); system_hostname= (cat/etc/osrelease);systemhostname=(hostname | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲'); systemc_env…(env | grep PATH);
mem_free= ( g r e p M e m F r e e / p r o c / m e m i n f o ) ; d i s k u s a g e = (grep MemFree /proc/meminfo); disk_usage= (grepMemFree/proc/meminfo);diskusage=(df -h);
system_uptime= ( u p t i m e ) ; s y s t e m l o a d = (uptime); system_load= (uptime);systemload=(cat /proc/loadavg);
system_ip=$(ip addr | grep 'inet ’ | grep -v 127.0.0.1 | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' | cut -f1 -d'…(/usr/sbin/dmidecode | grep -A 16 “Memory Device”|grep -E “Size|Locator”|grep -v Bank);
mem_total= ( g r e p M e m T o t a l / p r o c / m e m i n f o ) ; d a y 01 = (grep MemTotal /proc/meminfo); day01= (grepMemTotal/proc/meminfo);day01=(date +%Y);
day02= ( d a t e + d a y 03 = (date +%m); day03= (date+day03=(date +%d);
df -hiP | sed ‘s/Mounted on/Mounted/’ > /tmp/inode;
df -hTP | sed ‘s/Mounted on/Mounted/’ > /tmp/disk ;
diskdata=$(df -TP | sed ‘1d’ | awk ' 2 ! = " t m p f s " p r i n t ′ ) ; d i s k t o t a l = 2!="tmpfs"{print}'); disktotal= 2!="tmpfs"print);disktotal=(echo “$diskdata” | awk '{total+=KaTeX parse error: Expected 'EOF', got '}' at position 2: 3}̲END{print total…(echo “$diskdata” | awk '{total+=KaTeX parse error: Expected 'EOF', got '}' at position 2: 4}̲END{print total…((disktotal-diskused));
diskusedpercent=$(echo $disktotal $diskused | awk '{if($10){printf 100}else{printf “%.2f”,$2*100/KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲}'); inodedata…(df -iTP | sed ‘1d’ | awk ' 2 ! = " t m p f s " p r i n t ′ ) ; i n o d e t o t a l = 2!="tmpfs"{print}'); inodetotal= 2!="tmpfs"print);inodetotal=(echo “$inodedata” | awk '{total+=KaTeX parse error: Expected 'EOF', got '}' at position 2: 3}̲END{print total…(echo “$inodedata” | awk '{total+=KaTeX parse error: Expected 'EOF', got '}' at position 2: 4}̲END{print total…((inodetotal-inodeused));
inodeusedpercent=$(echo $inodetotal $inodeused | awk '{if($1
0){printf 100}else{printf “%.2f”,$2*100/KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲}'); report_Dis…((disktotal/1024/1024))“GB”;
report_DiskFree= ( ( d i s k f r e e / 1024 / 1024 ) ) " G B " ; r e p o r t D i s k U s e d P e r c e n t = " ((diskfree/1024/1024))"GB"; report_DiskUsedPercent=" ((diskfree/1024/1024))"GB";reportDiskUsedPercent="diskusedpercent”“%”;
report_InodeTotal= ( ( i n o d e t o t a l / 1000 ) ) " K " ; r e p o r t I n o d e F r e e = ((inodetotal/1000))"K"; report_InodeFree= ((inodetotal/1000))"K";reportInodeFree=((inodefree/1000))“K”;
report_InodeUsedPercent=“$inodeusedpercent”“%”;

OS_Version=$(awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 7: (NF-1)}̲' /etc/redhat-r…(cat /etc/redhat-release 2>/dev/null)
Kernel= ( u n a m e − r ) O S = (uname -r) OS= (unamer)OS=(uname -o)
Hostname= ( u n a m e − n ) S E L i n u x = (uname -n) SELinux= (unamen)SELinux=(/usr/sbin/sestatus | grep "SELinux status: " | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 3}̲') LastReboot=(who -b | awk '{print $3,KaTeX parse error: Expected 'EOF', got '}' at position 2: 4}̲') uptime=(uptime|exec awk ‘{ print $3 }’)

echo -e -n ;
#echo -e 主机名:“\t"KaTeX parse error: Undefined control sequence: \t at position 35: …echo -e 服务器IP:"\̲t̲"system_ip;
#echo -e 系统内核:”\t"KaTeX parse error: Undefined control sequence: \t at position 32: …cho -e 操作系统版本:"\̲t̲"system_version;
echo -e “系统: O S " e c h o − e " 发行版本: OS" echo -e "发行版本: OS"echoe"发行版本:Release”
echo -e “内核: K e r n e l " e c h o − e " 主机名: Kernel" echo -e "主机名: Kernel"echoe"主机名:Hostname”
echo -e “SELinux: S E L i n u x " e c h o − e " 语言 / 编码: SELinux" echo -e "语言/编码: SELinux"echoe"语言/编码:default_LANG”
echo -e “当前时间: ( d a t e + ′ e c h o − e " 最后启动: (date +'%F %T')" echo -e "最后启动: (date+echoe"最后启动:LastReboot”
echo -e “运行时间:$uptime”

echo -e 磁盘使用情况: “\t”“\t”" “; join /tmp/disk /tmp/inode | awk '{print $1,$2,”|“,$3,$4,$5,$6,”|“,$8,$9,$10,$11,”|“,$12}'| column -t;
echo -e -n “硬盘总容量(GB) $report_DiskTotal”;
echo -e “硬盘剩余(GB) $report_DiskFree”;
echo -e “硬盘使用率% $report_DiskUsedPercent”;
echo -e “Inode总量 $report_InodeTotal”;
echo -e “Inode剩余 $report_InodeFree”;
echo -e “Inode使用率% KaTeX parse error: Undefined control sequence: \t at position 42: …echo -e CPU核数:"\̲t̲"cpu_core_num;
echo -e 物理CPU个数:”\t"KaTeX parse error: Undefined control sequence: \t at position 29: …ho -e 逻辑CPU个数:"\̲t̲"logic_cpu_num;
echo -e 系统环境变量:”\t"" “KaTeX parse error: Undefined control sequence: \t at position 49: …cho -e CPU的主频:"\̲t̲"cpu_freq;
echo -e 内存总大小:”\t"KaTeX parse error: Undefined control sequence: \t at position 30: …cho -e 内存空闲空间:"\̲t̲"mem_free;
echo -e 时间/系统运行时间/当前登陆用户/系统过去1分钟/5分钟/15分钟内平均负载/“\t”"\n"KaTeX parse error: Undefined control sequence: \t at position 79: …个数/最大的pid值线程/ "\̲t̲""\n"system_load;
if [[ O S V e r s i o n > 7 ] ] ; t h e n c o n f = OS_Version > 7 ]];then conf= OSVersion>7]];thenconf=(systemctl list-unit-files --type=service --state=enabled --no-pager | grep “enabled”)
process=KaTeX parse error: Expected 'EOF', got '#' at position 85: …p ".service") #̲ report informa…(echo “KaTeX parse error: Expected 'EOF', got '#' at position 23: … wc -l)" #̲自启动服务数量 report…(echo “$process” | wc -l)” #运行中服务数量
echo “自启动服务数量 $report_SelfInitiatedService”
echo "运行中服务数量 r e p o r t R u n i n g S e r v i c e " e l s e c o n f = report_RuningService" else conf= reportRuningService"elseconf=(/sbin/chkconfig | grep -E “:on|:启用”)
process=KaTeX parse error: Expected 'EOF', got '#' at position 71: …unning|正在运行") #̲ report informa…(echo “KaTeX parse error: Expected 'EOF', got '#' at position 23: … wc -l)" #̲自启动服务数量 report…(echo “$process” | wc -l)” #运行中服务数量
echo “自启动服务数量 $report_SelfInitiatedService”
echo “运行中服务数量 $report_RuningService”
fi

conf=KaTeX parse error: Expected group after '^' at position 11: (grep -v "^̲#" /etc/rc.d/rc…/d’)
echo “$conf”

report information#自启动程序数量

report_SelfInitiatedProgram=“$(echo $conf | wc -l)”
echo “自启动程序数量 $report_SelfInitiatedProgram”
#网络信息
echo “网络信息”
if [[ $OS_Version < 7 ]];then
/sbin/ifconfig -a | grep -v packets | grep -v collisions | grep -v inet6
else
for i in $(ip link | grep BROADCAST | awk -F: ‘{print $2}’);do ip add show $i | grep -E “BROADCAST|global”| awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' | tr '\n' ' '…(ip route | grep default | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 3}̲'|uniq) DNS=(grep nameserver /etc/resolv.conf| grep -v “#” | awk ‘{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' | tr '\n' ','…//’)
echo “”
MAC=$(ip link | grep -v “LOOPBACK|loopback” | awk ‘{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' | sed 'N;s/\n…//’)
echo -e "IP地址 "“ s y s t e m i p " e c h o " M A C 地址 " " system_ip" echo "MAC地址 "" systemip"echo"MAC地址""MAC”
echo "默认网关 "“ G A T E W A Y " e c h o " D N S " " GATEWAY" echo "DNS "" GATEWAY"echo"DNS""DNS”

#端口信息
TCPListen=$(netstat -ntulp | column -t)
if [[ O S V e r s i o n < 7 ] ] ; t h e n A l l C o n n e c t = OS_Version < 7 ]];then AllConnect= OSVersion<7]];thenAllConnect=(ss -an | awk 'NR>1 {++s[KaTeX parse error: Expected 'EOF', got '}' at position 3: 1]}̲ END {for(k in …(ss -tan | awk 'NR>1 {++s[KaTeX parse error: Expected 'EOF', got '}' at position 3: 1]}̲ END {for(k in …TCPListen"
echo “------------------------------------------------------------------”
echo “$AllConnect”

report information

report_Listen_num=“ ( e c h o " (echo " (echo"TCPListen”| sed ‘1d’ | awk ‘/tcp/ {print $4}’ | awk -F: '{print KaTeX parse error: Expected 'EOF', got '}' at position 3: NF}̲' | sort | uniq…(netstat -ntulp | column -t| awk ‘/tcp/ {print $4}’ | awk -F: ‘{print $NF}’|sort|uniq|tr “\n” " “)”
echo " "
echo " TCP 开放端口 $report_Listen"
echo " TCP 端口数 $report_Listen_num"

#计划任务信息
Crontab=0
for shell in $(grep -v “/sbin/nologin” /etc/shells);do
for user in ( g r e p " (grep " (grep"shell" /etc/passwd | awk -F: ‘{print $1}’);do
crontab -l -u KaTeX parse error: Expected 'EOF', got '&' at position 19: …r >/dev/null 2>&̲1 status=?
if [ s t a t u s − e q 0 ] ; t h e n e c h o " status -eq 0 ];then echo " statuseq0];thenecho"user"
echo “-------------”
crontab -l -u u s e r l e t C r o n t a b = C r o n t a b + user let Crontab=Crontab+ userletCrontab=Crontab+(crontab -l -u $user | wc -l)
echo “”
fi
done
done

scheduled task

find /etc/cron* -type f | xargs -i ls -l {} | column -t
let Crontab=Crontab+$(find /etc/cron* -type f | wc -l)

report information

echo “计划任务数 $Crontab”

#sudoer权限
conf=KaTeX parse error: Expected group after '^' at position 11: (grep -v "^̲#" /etc/sudoers…/d’)
echo “/etc/sudoers用户权限设置如下”
echo “$conf”

#安装信息
echo “近期安装软件包信息”
echo “------------”
rpm -qa --last | head | column -t

if [ $(ps -ef | grep defunct | grep -v grep | wc -l) -ge 1 ];then
echo “”
echo “zombie process”;
echo “--------”
ps -ef | head -n1
ps -ef | grep defunct | grep -v grep
fi
echo “”
echo “MEM 使用 TOP10”
echo “-------------”
echo -e “PID %MEM RSS COMMAND
$(ps aux | awk ‘{print $2, $4, $6, $11}’ | sort -k3rn | head -n 10 )”| column -t
echo “”
echo “cpu 使用 TOP10”
echo “------------”
top b -n1 | head -17 | tail -11

#登录信息
echo “近期登陆信息”
echo “------------”
#last 不同系统版本格式不统一,此处不做格式化处理日期
last | head
#服务检查
echo “服务信息检查”
echo “------------”
sh ./check.sh $CHECK_ERROR_LOG
echo -e ‘************************************************************************************************************************’

2.check.sh 服务检查脚本

#!/bin/bash
#加载配置文件
#"-------------------------------------配置项开始------------------------------------------"

#是否开通用启日志备份
LOG_BAK=false
#是否启用应用备份
APP_BACK=false
#应用备份目录,支持多目录,将自动过滤不存在目录及文件
BACK_DIR='/opt/workspace/ferry_web_bak0423/ /opt/workspace/ferry/fadsfsaf '
#内存百分比
MEM_CONFIG=80
#CPU百分比
CPU_CONFIG=90
#不达标的磁盘百分比
DISK_CONFIG=80
#合格的openssl版本
#OPENSSL_CONFIG=(1.1.1k 1.1.1j 1.1.1q)
#openssl版本配置,支持正则,无则无需修改
OPENSSL_CONFIG=(1.1.1c 1.1.1b 1.1.1a 3.0.8)
#nginx版本配置,支持正则,无则无需修改
NGINX_VERSION_CONFIG=(1.22.0 1.22.1 1.18.0)
#NGINX_VERSION_CONFIG=(1.22.0 1.22.1 1.18.0)
#tomcat版本配置,支持正则,无则无需修改
TOMCAT_VERSION_CONFIG=(8.51.88.0 8.5.76)
#activemq版本配置,支持正则,无则无需修改
ACTIVEMQ_VERSION_CONFIG=(5.15.4 5.18.8)
#rabbitmq版本配置,支持正则,无则无需修改
RABBITMQ_VERSION_CONFIG=(3.8.1)
#zookeeper版本配置,支持正则,无则无需修改
ZOOKEEPER_VERSION_CONFIG=(3.8.1)
#mongo版本配置,支持正则,无则无需修改
MONGO_VERSION_CONFIG=(v4.41.212 v4.0.23)
#jetty版本配置,支持正则,无则无需修改
JETTY_VERSION_CONFIG=(9.4.22.v20191022)
#redis版本配置,支持正则,无则无需修改
REDIS_VERSION_CONFIG=(6.2.7)
#jdk版本配置,支持正则
JAVA_VERSION_CONFIG=(1.8.0_202)
#MONGO_VERSION_CONFIG=(v4.4.21 v4.0.23)
#日志备份的日志大小高于剩余空间的百分比时不进行备份
DISK_RANGE_PERCENT=80
#触发备份的文件大小
LOG_BAK_SIZE=20M
#需要备份的文件类型
LOG_BAK_TYPE='-name "*.log" -o -name "*.out"'
#备份的日志目录
LOG_BASE_CHECK_DIR=/opt
#可执行文件检查目录
EXECUTABLE_FILE_CHECK_DIR=/opt
#check需要输出日志的存放文件
mkdir -p ./log
#nginx日志100000行命中次数
ATTACK_NUMBER=6000
#tomcat关键日志截取,错误日志,不区分大小写
ERROR_LOG_KEY_WORK="OutOfMemoryError|PermGen space|StackOverflowError|TimeoutException|Java heap space|GC overhead limit exceeded|IOException|IllegalStateException|IllegalArgumentException|NullPointerException|NoClassDefFoundError|ClassNotFoundException|SocketTimeoutException|ConnectException|Connection timed out|net.TimeoutException|faFlsj"

#"-------------------------------------配置项结束------------------------------------------"

date=`date +%Y%m%d`;
time=`date +%H%M%S`;
CHECK_ERROR_LOG="./log/${date}_${time}_check.log"
if [ -n "$1" ]; then
CHECK_ERROR_LOG="$1"
fi
echo -e "巡检时间:$date $time"
#服务巡检项
inspectionItems=( 
	'内存情况'  
	'磁盘情况'
	'CPU检查'
	'防火墙开启情况'
	'检查密码策略'
	'检查空口令'
	'缺省目录权限'
	'潜在危险文件检查'
	'环境变量检查'
	'suid_guid授权检查'
	'可执行文件检查权限检查'
	'检查进程启动用户'
	'检查tomcat指标'
	'UIDS超级用户检查'
	'nginx日志检查'
	'openssl版本检查'
	'nginx版本检查'
	'tomcat版本检查'
	'mongo版本检查'
	'jetty版本检查'
	'redis版本检查'
	'activemq版本检查'
	'rabbitmq版本检查'
	'zookeeper版本检查'
	'jdk版本检查'
)
					 
echo -e "检查项\t\t\t是否符合要求\t\t\t备注"
#内存情况
MEM=`free -m | sed -n "2p" | awk '{printf $3/$2*100}'` ; 
#磁盘情况
asc=`df -Ph |grep -v Filesystem | grep -v 文件系统| grep -v Filesystem |  awk  '{print $5,$6}' |awk -v var=$DISK_CONFIG -F '%' '{if($1>=var){print $1}}'` 
passmax=`cat /etc/login.defs | grep PASS_MAX_DAYS | grep -v ^# | awk '{print $2}'`
passlen=`cat /etc/login.defs | grep PASS_MIN_LEN | grep -v ^# | awk '{print $2}'`
#CPU检查
CPU=`top -bn 1 -c | sed -n '3p' | awk -F ':' '{print $2}'| awk '{printf $1}'`
passcheck=`sudo cat /etc/shadow | awk -F: '($2 == "" ) { print $1 }'`;
umask1=`cat /etc/profile | grep umask | grep -v ^# | awk '{print $2}'`;
umask2=`cat /etc/csh.cshrc | grep umask | grep -v ^# | awk '{print $2}'`;
umask3=`cat /etc/bashrc | grep umask | grep -v ^# | awk 'NR!=1{print $2}'`; 
if [ ` echo "$MEM>=$MEM_CONFIG"|bc`  -eq "1" ];
	then echo  -e "${inspectionItems[0]}\t\t不合格\t\t请检查内存是否超过$MEM_CONFIG"
else 
	echo -e "${inspectionItems[0]}\t\t合格"
fi
#磁盘情况
if test -n $asc 
	then echo -e "${inspectionItems[1]}\t\t合格"
else 
	 echo -e "${inspectionItems[1]}\t\t不合格\t\t请确保磁盘空间占用$DISK_CONFIG以下"
fi
#CPU检查
if [ ` echo "$CPU<=$CPU_CONFIG"|bc ` -eq "1" ]
	then echo -e "${inspectionItems[2]}\t\t\t合格"
else 
	 echo -e "${inspectionItems[2]}\t\t\t不合格\t\t请检查CPU是否超过$CPU_CONFIG"
fi
#防火墙检查
if systemctl is-active --quiet iptables || systemctl is-active --quiet firewalld  
	then echo -e "${inspectionItems[3]}\t\t合格"
else 
	echo -e "${inspectionItems[3]}\t\t不合格\t\t请检查firewalld或iptables防火墙是否开启"
fi
#检查密码策略  
if [ $passmax -le 90 -a $passmax -gt 0 -a $passlen -ge 8 ] 
	then echo -e "${inspectionItems[4]}\t\t合格"
else 
	echo -e "${inspectionItems[4]}\t\t不合格\t\t请检查/etc/login.defs是否设置密码策略"
fi
#检查空口令
if test -z $passcheck 
	then echo -e "${inspectionItems[5]}\t\t合格"
else 
	echo -e "${inspectionItems[5]}\t\t不合格\t\t请检查/etc/shadow是否存在空口令账号"
fi
#缺省目录权限

flags=0; 
for i in $umask1 ; 
do  
	if [ $i != "027" ];
		then flags=1; break; 
	fi 
done;  
flags1=0; 
for j in $umask2; 
do  
	if [ $j != "027" ];
		then flags1=1;   break ; 
	fi 
done ;  
flags2=0; 
for k in $umask3; 
do  
	if [ $k != "027" ];
		then flags2=1;   break ; 
	fi 
done ; 
if  [ $flags == 0 -a  $flags1 == 0 -a $flags2 == 0 ];
	then echo -e "${inspectionItems[6]}\t\t合格";
else 
	echo -e "${inspectionItems[6]}\t\t不合格\t\t请检查/etc/profile,etc/csh.cshrc,etc/bashrc是否均已设置umask";
fi
#潜在危险文件检查
if [ $( find / -maxdepth 3 -name "*.hosts.equiv" -or -name "*.rhosts" -or -name "*.netrc"  -or -name "*id_rsa" 2>/dev/null | wc -l )  -eq 0 ] ;
	then echo -e "${inspectionItems[7]}\t合格";
else 
	echo -e "${inspectionItems[7]}\t不合格\t\t请检查服务器是否存在.hosts.equiv,.rhosts,.netrc,*id_rsa类文件";
fi
#root用户环境变量的安全性
dirPri=$(find $(echo $PATH | tr ':' ' ') -type d \( -perm -0777 \) 2> /dev/null);
if [  -z "$dirPri" ] ; 
	then echo -e "${inspectionItems[8]}\t\t合格";
else  
	echo -e "${inspectionItems[8]}\t\t不合格\t\t请检查环境变量是否存在777权限目录";
fi
#suid_guid授权检查
if [ $( find / -perm -4000 -o -perm -2000 ! -user root -type f -print 2>/dev/null| wc -l )  -eq 0 ] ;
	then echo -e "${inspectionItems[9]}\t合格";
else 
	echo -e "${inspectionItems[9]}\t不合格\t\t请检查是否存在非root认证的suid和guid文件";
fi
#可执行文件检查权限检查
if [ $( find $EXECUTABLE_FILE_CHECK_DIR -type f -executable \( -name "*.exe" -o -name "*.sh" -o -name "*.py"  -o -name "*.coff"   -o -name "*.elf" \)  -exec ls -l {} \; | awk '$1 ~ /x$/{ print $0}' | wc -l )  -eq 0 ] ;
	then echo -e "${inspectionItems[10]}\t合格";
else
	echo -e "${inspectionItems[10]}\t不合格\t\t请检查 $EXECUTABLE_FILE_CHECK_DIR 目录下是否存在*.exe,*.sh,*.py,*.coff,*.elf类可执行(-executable)文件权限";
fi
#检查进程启动用户
if [ $(lsof -i -P -n | grep LISTEN | grep -v 'ssh\|rpc\|agen\|master' | awk '$3 ~ /root$/{print}'|wc -l)  -eq 0 ] ;
	then echo -e "${inspectionItems[11]}\t合格";
else 
	echo -e "${inspectionItems[11]}\t不合格\t\t请检查是否存在root用户启动的进程";
fi
#版本比较方法 version_elements:可用版本,支持正则,check_v:当前版本
function check_version {
		#获取${!1} 第一个参数所对应变量的值为供选择的版本数组,第二个参数$2为需要检查的版本
        local version_elements=("${!1}")
        local check_v=$2
        for i in "${version_elements[@]}"; do
                if [[ "$check_v" =~ "$i" ]] ;
                then
                   return 0
                fi;
        done
        return 1
}
#检查tomcat指标
for tomcat_process in $(pgrep -f "catalina.home"); 
do  
	tomcat_path=$(ps -p $tomcat_process -o args= | grep -E -o "catalina.home=.* " | cut -d "=" -f2 | sed 's/.$//'| awk '{print $1}') ; 
	tomcat_conf="${tomcat_path}/conf/server.xml"
	tomcat_port="lsof -i -P -n | grep $tomcat_process | grep -v 8005|head -n 1 | awk '{print $9}' | cut -d ':' -f 2"
	version_path="${tomcat_path}/bin/version.sh"
	tomcat_version=`$version_path | grep 'Server number'| cut -d ' ' -f 4`
	flag="true";
	echo  -e "检查tomcat:${tomcat_path}" >> $CHECK_ERROR_LOG;
	echo  -e "--------------------------------\n" >> $CHECK_ERROR_LOG;
	if grep -q 'user username="admin" password=' $tomcat_path/conf/tomcat-users.xml; then
		echo -e "${inspectionItems[12]}:不合格; tomcat位置:$tomcat_path;Tomcat 启用了默认用户及密码. 请删除默认用户或修改默认密码."  >> $CHECK_ERROR_LOG
		flag=false;
	fi
	
	if [ $(cat  $tomcat_conf | grep 'shutdown="SHUTDOWN"'|wc -l)  -eq 0 ] ;
		then echo -e "${inspectionItems[12]}\t\t合格\t\t tomcat位置:$tomcat_path" >> $CHECK_ERROR_LOG;
	else 
		echo -e "${inspectionItems[12]}:不合格; tomcat位置:$tomcat_path;配置文件启用了SHUTDOWN来关闭程序" >> $CHECK_ERROR_LOG;
		flag=false
	fi;  
	if grep -q 'SSLEnabled="true"'   $tomcat_path/conf/server.xml; then
		echo "Tomcat is running with SSL enabled." >>$CHECK_ERROR_LOG;
	fi	
	if curl -sSf "http://localhost:$TOMCAT_PORT/" 2>&1>/dev/null; 
	then         
		  :   
	else
		flag=false;
		echo "Tomcat($tomcat_path) 服务无响应,请检查服务是否正常">> $CHECK_ERROR_LOG;     
	fi
	
	
	
	#tomcat文件权限检查
	if [[ $(find $tomcat_path  \( -path $tomcat_path/logs -o -path $tomcat_path/conf \) -prune -o    -type f -perm -744  ! -perm  744  -print |wc -l)  -eq 0 ]] 
	then	
		:
		echo ""
	else 
		flag=false;
		echo "Tomcat($tomcat_path) 文件权限应设置小于等于744,请设置:find $tomcat_path  \( -path $tomcat_path/logs -o -path $tomcat_path/conf \) -prune -o    -type f -perm -744  ! -perm  744  -print   -exec chmod 744 {} \; ">> $CHECK_ERROR_LOG;  
	fi
	#tomcat目录权限检查
	if [[ $(find $tomcat_path  \( -path $tomcat_path/logs -o -path $tomcat_path/conf \) -prune -o    -type d -perm -644  ! -perm  644  -print |wc -l)  -eq 0 ]] 
	then	
		:
	else 
		flag=false;
		echo "Tomcat($tomcat_path) 目录权限应设置小于等于644,请设置:find $tomcat_path  \( -path $tomcat_path/logs -o -path $tomcat_path/conf \) -prune -o    -type d -perm -644  ! -perm  644  -print   -exec chmod 644 {} \; ">> $CHECK_ERROR_LOG;  
	fi
	#tomcat日志权限检查
	if [[ $(find $tomcat_path/logs/* $tomcat_path/conf/* -type f -perm -600   ! -perm  600  |wc -l)  -eq 0 ]] 
	then	
		:
	else 
		flag=false;
		echo "Tomcat($tomcat_path/log  $tomcat_path/conf/) 目录权限应设置小于等于600,请设置:find $tomcat_path/logs/* $tomcat_path/conf/* -type f -perm -600   ! -perm  600  -exec chmod 600 {} \; ">> $CHECK_ERROR_LOG;  
	fi
	
	#禁用tomcat版本号
	if [ -n "$tomcat_version" ]; 
	then
		flag=false;
		echo "请禁用$tomcat_path版本号  vim $tomcat_path/lib/catalina.jar  then search 'ServerInfo.properties' to edit set server.number=''   " >> $CHECK_ERROR_LOG; 
	fi
	
	
	if [[ "$flag" == "true" ]];
	then 
		echo -e "${inspectionItems[12]}\t\t合格\t\t tomcat位置:$tomcat_path";
		echo -e "${inspectionItems[12]}\t\t合格" >> $CHECK_ERROR_LOG;
		echo "                                " >> $CHECK_ERROR_LOG;
	else 
		echo -e "${inspectionItems[12]}\t\t不合格\t\t tomcat位置:$tomcat_path,详细请看 $CHECK_ERROR_LOG 日志文件";
		echo -e "${inspectionItems[12]}\t\t不合格" >> $CHECK_ERROR_LOG;
		echo "                                " >> $CHECK_ERROR_LOG;
	fi
	echo "------$tomcat_path 相关错误日志----------" >> $CHECK_ERROR_LOG
	echo "关键字:$ERROR_LOG_KEY_WORK" >> $CHECK_ERROR_LOG
	#tomcat 日志分析
	#截取10日内日志文件1000000行分析,(没做日志切割的则是查的1000000行分析)关键错误日志前后20行,采用正则匹配
	find $tomcat_path/logs/ -type f -mtime -10 -name "*catalina*"  -exec  tail -n 100000 {} \;| grep -E -i -A 20 -B 20 "$ERROR_LOG_KEY_WORK" >> $CHECK_ERROR_LOG;
	#grep -E -i -A 20 -B 20 $ERROR_LOG_KEY_WORK >> $CHECK_ERROR_LOG;
	echo "--------------------------------------------------------------" >> $CHECK_ERROR_LOG
done; 

#if [ $flag = "true" ];
#  then echo -e "${inspectionItems[12]}\t\t合格";
#else
#  echo -e "${inspectionItems[12]}\t\t不合格";
#fi
#UIDS检查,是否存在除root外的超级用户
flag=true;
UIDS=`awk -F[:] 'NR!=1{print $3}' /etc/passwd`;
for i in $UIDS;
do if [ $i = 0 ];
	then  echo flag=false;break;
fi; 
done;
if [ $flag = "true" ];
  then echo -e "${inspectionItems[13]}\t合格";
else
  echo -e "${inspectionItems[13]}\t不合格\t\t请检查/etc/passwd是否存在除root外的超管用户";
fi
#nginx相关检查
nginx_pids=`ps -ef|grep nginx | grep master| grep -v grep | awk '{print $2}'`; 
for nginx_pid in ${nginx_pids[@]};do 
	nginxexe=`ls -l /proc/$nginx_pid/ |grep exe |awk '{print $11}'`;
	openssl_v=`$nginxexe  -V 2>&1 | tr '[:upper:]' '[:lower:]'| grep -o "openssl.*" |head -n 1|awk '{print $2}'`;
	nginx_v=`$nginxexe -v 2>&1 | cut -d '/' -f 2`; 
	#nginx日志检查
	nginx_log=$(
	for log_path in $(ls -l /proc/$nginx_pid/fd/ |grep .log|grep -v error | awk '{print $11}' |uniq);
	do 
		recent_access=$(tail -n 100000 $log_path);access_count=$(echo "$recent_access" | awk '{print $1}' | sort | uniq -c) ;  
		echo "$access_count" | while read line; 
		do  
		count=$(echo "$line" | awk '{print $1}'); ip=$(echo "$line" | awk '{print $2}');  
			if [ $count -gt $ATTACK_NUMBER ]; 
				then   echo "Warning: IP $ip has $count requests in the last $threshold lines;当前时间:`date`rrrr" ; 
			fi;
		done; 
	done);
	#openssl日志检查
	if [ $(echo $nginx_log|awk  'BEGIN{RS="rrrr"} {print}' |sed '/^$/d'|wc -l)  -eq 0 ] ;
	then echo -e "${inspectionItems[14]}\t\t合格\t\t nginx位置:$nginxexe";
	else 
		echo -e "${inspectionItems[14]}\t\t不合格\t\t nginx位置:$nginxexe;请检查是否近期是否存在访问超过$ATTACK_NUMBER次上的IP地址";
	fi
	#openssl版本检查
	if check_version "OPENSSL_CONFIG[@]"  "$openssl_v";
	#if [[ "${OPENSSL_CONFIG[*]}" =~ "$openssl_v" ]] ;
	   then echo -e "${inspectionItems[15]}\t\t合格\t\t nginx位置:$nginxexe";
	else 
		echo -e "${inspectionItems[15]}\t\t不合格\t\t nginx位置:$nginxexe;当前版本:$openssl_v,请安装指定版本:${OPENSSL_CONFIG[*]}";
	fi;
	#nginx版本检查
	if check_version  "NGINX_VERSION_CONFIG[@]"  "$nginx_v";
	#if [[ "${NGINX_VERSION_CONFIG[*]}" =~ "$nginx_v" ]] ;
	   then echo -e "${inspectionItems[16]}\t\t合格\t\t nginx位置:$nginxexe";
	else 
		echo -e "${inspectionItems[16]}\t\t不合格\t\t nginx位置:$nginxexe;当前版本:$nginx_v,请安装指定版本:${NGINX_VERSION_CONFIG[*]}";
	fi;
	
	#nginx日志输出
	echo "------$nginxexe 相关日志----------" >> $CHECK_ERROR_LOG
	echo -e "匹配条件:同一IP在最近100000行内出现超过 $ATTACK_NUMBER 次" >> $CHECK_ERROR_LOG
	echo -n $nginx_log|awk  'BEGIN{RS="rrrr"} {print}' |sed '/^$/d' >> $CHECK_ERROR_LOG
	echo "--------------------------------------------------------------" >> $CHECK_ERROR_LOG
done
#tomcat版本检查
for tomcat_process in $(pgrep -f "catalina.home"); 
do  
	tomcat_path=$(ps -p $tomcat_process -o args= | grep -E -o "catalina.home=.* " | cut -d "=" -f2 | sed 's/.$//'| awk '{print $1}') ; 
	version_path="${tomcat_path}/bin/version.sh"
	#version_path=$(ps -p $tomcat_process -o args= | grep -E -o "catalina.home=.* " | cut -d "=" -f2 | sed 's/.$//'| awk '{print $1"/bin/version.sh"}')
	#tomcat_path=$(ps -p $tomcat_process -o args= | grep -E -o "catalina.home=.* " | cut -d "=" -f2 | sed 's/.$//'| awk '{print $1"/conf/server.xml" }') ; 
	tomcat_version=`$version_path | grep 'Server number'| cut -d ' ' -f 4`
	#如果tomcat版本号显示被禁用,可以使用此项查看版本号
	tomcat_version_r=`cat $tomcat_path/RELEASE-NOTES |grep "Tomcat Version"|awk '{print $4}'`
	if check_version  "TOMCAT_VERSION_CONFIG[@]"  "$tomcat_version" -o  check_version  "TOMCAT_VERSION_CONFIG[@]"  "$tomcat_version_r" ;
	#if [[ "${TOMCAT_VERSION_CONFIG[*]}" =~ "$tomcat_version" ]] ;
		then echo -e "${inspectionItems[17]}\t\t合格\t\t tomcat位置:$tomcat_path";
	else 
		echo -e "${inspectionItems[17]}\t\t不合格\t\t tomcat位置:$tomcat_path;当前版本:$tomcat_version,请安装指定版本:${TOMCAT_VERSION_CONFIG[*]}";
	fi; 
done; 
#mongodb版本检查
for mongo_pid in $(pgrep -f "mongo"); 
do 

	mongo_exe=`ls -l /proc/$mongo_pid/ | grep exe | awk '{print $11}'`
	mongo_v=`$mongo_exe  --version | head -n 1 | awk '{print $3}'`
	if check_version  "MONGO_VERSION_CONFIG[@]"  "$mongo_v";
	#if [[ "${MONGO_VERSION_CONFIG[*]}" =~ "$mongo_v" ]] ;
		then echo -e "${inspectionItems[18]}\t\t合格\t\t mongo位置:$mongo_exe";
	else 
		echo -e "${inspectionItems[18]}\t\t不合格\t\t mongo位置:$mongo_exe;当前版本:$mongo_v,请安装指定版本:${MONGO_VERSION_CONFIG[*]}";
	fi;
done
# head -n 1 /opt/workspace/jetty-distribution-9.4.22.v20191022/VERSION.txt | awk '{print $1}'
for jetty_pid in $(pgrep -f "jetty"); 
do 
	jetty_path=`ls -l /proc/$jetty_pid/ | grep cwd | awk '{print $11}'`
	jetty_v=`head -n 1  $jetty_path/VERSION.txt  | awk '{print $1}'|cut -d '-' -f 2`
	if check_version  "JETTY_VERSION_CONFIG[@]"  "$jetty_v";
	#if [[ "${JETTY_VERSION_CONFIG[*]}" =~ "$jetty_v" ]] ;
		then echo -e "${inspectionItems[19]}\t\t合格\t\t jety位置:$jetty_path";
	else 
		echo -e "${inspectionItems[19]}\t\t不合格\t\t jety位置:$jetty_path;当前版本:$jetty_v,请安装指定版本:${JETTY_VERSION_CONFIG[*]}";
	fi;
done
for redis_pid in $(pgrep -f "redis-server"); 
do
	redis_exe=`ls -l /proc/$redis_pid/ | grep exe | awk '{print $11}'`
	redis_v=`$redis_exe -v | awk '{print $3}' | cut -d '='  -f 2` 
	if check_version  "REDIS_VERSION_CONFIG[@]"  "$redis_v";
	#if [[ "${REDIS_VERSION_CONFIG[*]}" =~ "$redis_v" ]] ;
		then echo -e "${inspectionItems[20]}\t\t合格\t\t redis位置:$redis_exe";
	else 
		echo -e "${inspectionItems[20]}\t\t不合格\t\t redis位置:$redis_exe;当前版本:$redis_v,请安装指定版本:${REDIS_VERSION_CONFIG[*]}";
	fi;
done
#检查activemq版本
for activemq_process in $(pgrep -f "Dactivemq.home"); 
do  
	activemq_path=$(ps -p $activemq_process -o args= | grep -E -o "Dactivemq.home=.* " | cut -d "=" -f2 | sed 's/.$//'| awk '{print $1}') ; 
	version_path="${activemq_path}/bin/activemq"
	activemq_v=`$version_path --version|grep ActiveMQ | awk '{print $2}'`
	if check_version  "ACTIVEMQ_VERSION_CONFIG[@]"  "$activemq_v";
	#if [[ "${ACTIVEMQ_VERSION_CONFIG[*]}" =~ "$activemq_v" ]] ;
		then echo -e "${inspectionItems[21]}\t合格\t\t activemq位置:$activemq_path";
	else 
		echo -e "${inspectionItems[21]}\t不合格\t\t activemq位置:$activemq_path;当前版本:$activemq_v,请安装指定版本:${ACTIVEMQ_VERSION_CONFIG[*]}";
	fi;  
done; 
#检查 rabbitmq版本
rabbitmq_pid=`pgrep rabbitmq|head -n 1`
if [ -n "$rabbitmq_pid" ]; then   
	rabbitmq_v=`rabbitmqctl status | grep RabbitMQ | awk '{print $3}' 2>/etc/null`
	rabbitmq_path=`ps -p $rabbitmq_pid -o args= | awk '{print$2}'`
	if check_version  "RABBITMQ_VERSION_CONFIG[@]"  "$rabbitmq_v";
	#if [[ "${RABBITMQ_VERSION_CONFIG[*]}" =~ "$rabbitmq_v" ]] ;
		then echo -e "${inspectionItems[22]}\t合格\t\t rabbitmq位置:$rabbitmq_path";
	else 
		echo -e "${inspectionItems[22]}\t不合格\t\t rabbitmq位置:$rabbitmq_path;当前版本:$rabbitmq_v,请安装指定版本:${RABBITMQ_VERSION_CONFIG[*]}";
	fi;
fi
#检查zookeeper版本
for zookeeper_pid in $(pgrep -f "zookeeper"); 
do
	zookeeper_exe=`ll /proc/$zookeeper_pid/ | grep  cwd | awk '{print $11}'`;
	zookeeper_v=`$zookeeper_exe/zkServer.sh version  2>/etc/null | grep version | awk '{print $4}'`;
	if check_version  "ZOOKEEPER_VERSION_CONFIG[@]"  "$zookeeper_v";
	#if [[ "${ZOOKEEPER_VERSION_CONFIG[*]}" =~ "$zookeeper_v" ]] ;
		then echo -e "${inspectionItems[23]}\t合格\t\t zookeeper位置:$rabbitmq_path";
	else 
		echo -e "${inspectionItems[23]}\t不合格\t\t zookeeper位置:$zookeeper_exe;当前版本:$zookeeper_v,请安装指定版本:${ZOOKEEPER_VERSION_CONFIG[*]}";
	fi;
done

#检查jdk版本
java_v=`java -version 2>&1 | grep version | awk '{print $3}' | tr -d \"`
if [ -n "$java_v" ]; then
	if check_version  "JAVA_VERSION_CONFIG[@]"  "$java_v";
	#if [[ "${JAVA_VERSION_CONFIG[*]}" =~ "$java_v" ]] ;
		then echo -e "${inspectionItems[24]}\t\t合格";
	else 
		echo -e "${inspectionItems[24]}\t\t不合格\t\t\t 当前版本:$java_v,请安装指定版本:${JAVA_VERSION_CONFIG[*]}";
	fi;

fi

#是否开启通用日志备份功能
if [[ "$LOG_BACK" = "true"  ]];then
	echo "通用备份日志"
	echo "------------"
#此处禁止缩进
readarray -t files <<EOF
$(find $LOG_BASE_CHECK_DIR -type f  \( -name "*.log" -o -name "*.out" \)   -size +$LOG_BAK_SIZE  -exec du -cb {} +)
EOF
	need_space=`for file in "${files[@]}"; do   echo $file  ;  done | grep total | cut -d ' ' -f 1`;
	if [ "${#files[@]}" -ne 0 -a -n "$need_space"  ] ;then  
		disk_free=`df --output=avail /opt/ | tail -n 1| awk -v var=$DISK_RANGE_PERCENT '{printf "%d\n",  $1*1024*var/100}'`;
		if [ ` echo "$disk_free >  $need_space"|bc ` -eq "1" ]; then
			date=`date +%Y%m%d`;
			time=`date +%H%M%S`;
			mkdir -p /opt/bak/$date; 
			#压缩日志
			for file in "${files[@]}"; do   echo $file ;  done | grep -v total|awk '{print $2}' | xargs tar --absolute-names -czvf /opt/bak/$date/archive_${time}.tar.gz >/dev/null 2>&1 ;
			#清空日志
			for file in "${files[@]}"; do   echo $file ;  done |grep -v "total" | awk '{system("echo '' >" $2)}';
			echo -e "$LOG_BASE_CHECK_DIR目录下所有$LOG_BAK_TYPE类型 日志备份完成,备份文件:/opt/bak/$date/archive_${time}.tar.gz";
			echo -e "如需要还原备份日志请使用 tar -zxvf /opt/bak/$date/archive_${time}.tar.gz   --absolute-names 命令,命令将解压备份日志到原来目录并覆盖掉现有日志,请确认后使用" 
		else  
			echo -e "opt可用磁盘空间不足,需要空间$need_space,所需空间$disk_free,无法压缩日志";
		fi ; 
	else 
		echo -e  "$LOG_BASE_CHECK_DIR目录无可压缩日志($LOG_BAK_TYPE)文件";
	fi;
fi;
#备份

 
if [[ "$APP_BACK" = "true"  ]];then 
	echo "应用服务备份\n备份目录$BACK_DIR"
	echo "------------"
	echo $BACK_DIR | awk '{system("ls -d  " $0) }' 2>&1 >/dev/null|awk '{print $4 "目录不存在,将忽视此目录备份"}'
	FILTING_DIR=`echo $BACK_DIR | awk '{system("ls -d  " $0) }' 2>/dev/null`
	need_space=`du -scb  $FILTING_DIR |  grep total | awk '{print $1}'`
	disk_free=`df --output=avail /opt/ | tail -n 1|  awk -v var=$DISK_RANGE_PERCENT '{printf "%d\n",  $1*1024*var/100}'`;
	if [ ` echo "$disk_free >  $need_space"|bc ` -eq "1" ]; then
		date=`date +%Y%m%d`;
		time=`date +%H%M%S`;
		mkdir -p /opt/bak/$date; 
		#压缩备份
		tar  --absolute-names -zcvf /opt/bak/$date/apps_${time}.tar.gz  $FILTING_DIR >/dev/null 2>&1 
		echo -e " $BACK_DIR目录备份完成,备份文件:/opt/bak/$date/apps_${time}.tar.gz";
		echo -e "如需要还原备份日志请使用 tar -zxvf /opt/bak/$date/apps_${time}.tar.gz   --absolute-names 命令,命令将解压备份日志到原来目录并覆盖掉现有日志,请确认后使用" 
	else  
		echo -e "opt可用磁盘空间不足,需要空间$need_space,所需空间$disk_free,无法压缩日志";
	fi ;
fi

3.邮件发送脚本

sendMail.sh
#/bin/bash
date=date +%Y%m%d;
time=date +%H%M%S;
Hostname= ( u n a m e − n ) s y s t e m i p = (uname -n) system_ip= (unamen)systemip=(ip addr | grep 'inet ’ | grep -v 127.0.0.1 | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' | cut -f1 -d'…{date} t i m e c h e c k . l o g " C H E C K I N S P E C T L O G = " . / l o g / {time}_check.log" CHECK_INSPECT_LOG="./log/ timecheck.log"CHECKINSPECTLOG="./log/{date}KaTeX parse error: Expected 'EOF', got '#' at position 21: …}_inspect.log" #̲MAIL_CONTENT=`s…CHECK_ERROR_LOG"`
#echo M A I L C O N T E N T ∣ m a i l x − s " MAIL_CONTENT | mailx -s " MAILCONTENTmailxs"Hostname 服务器巡检报告" -a C H E C K E R R O R L O G y a n g l a n g @ d h c c . c o m . c n s h i n s p e c t i o n c h e c k t o o l . s h " CHECK_ERROR_LOG yanglang@dhcc.com.cn sh inspection_check_tool.sh " CHECKERRORLOGyanglang@dhcc.com.cnshinspectionchecktool.sh"CHECK_ERROR_LOG" > “ C H E C K I N S P E C T L O G " e c h o " 测试服务巡检报告 " ∣ m a i l x − s " CHECK_INSPECT_LOG" echo "测试服务巡检报告" | mailx -s " CHECKINSPECTLOG"echo"测试服务巡检报告"∣mailxs"Hostname ($system_ip) 服务器巡检报告” -a $CHECK_ERROR_LOG -a $CHECK_INSPECT_LOG xxx@qq.com bbb@qq.com

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DancingShoes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值