1 前言
一个问题,一篇文章,一出故事
笔者生产的服务器需要使用谷歌推送,但是DNS解析出来的IP有的通讯被拦截有的通讯正常,于是产生使用shell脚本筛选DNS解析记录的想法(个人认为应当由程序员解决,运维脚本只能用于临时解决问题)。
2 最佳实践
2.1 创建脚本
mkdir ~/scripts/ vim ~/scripts/dnsRecordMaintenance.sh
加入如下代码,
#!/bin/bash domainName="$1" domainPort="$2" hostsPath="$3" getTouchIPs() { testDomain="$1" testPort="$2" if [ -z "$testDomain" ]; then echo "Please enter test domain name!" return 1 fi if [ -z "$testPort" ]; then echo "Please enter test port!" return 1 fi testIPs=`nslookup "$testDomain" | grep -v "#53" | grep Address: | cut -d":" -f2 | sed 's/ //g'` testIPsCount=`echo "$testIPs" | wc -w` if [ "$testIPsCount" = "0" ]; then echo "No DNS resolution record!" return 1 fi ipList="" for i in $testIPs ; do testIP="$i" ipTestCount=`wget -t1 -T3 --output-document=/dev/nul "$testIP":"$testPort" 2>&1 | grep connected | wc -l` if [ "$ipTestCount" = "1" ] && [ "$ipList" != "" ]; then ipList="$ipList"" ""$testIP" fi if [ "$ipTestCount" = "1" ] && [ "$ipList" = "" ]; then ipList="$testIP" fi done echo "$ipList" return 0 } addHosts() { addIPs="$1" addDomain="$2" hostsPath="$3" if [ -z "$addIPs" ]; then echo "Please enter add IP list!" return 1 fi if [ -z "$addDomain" ]; then echo "Please enter add domain name!" return 1 fi hostIPs=`grep "$addDomain" "$hostsPath" | cut -d" " -f1` hostIPsCont=`echo "$hostIPs" | wc -w` if [ "$hostIPsCont" = "0" ]; then for i in $addIPs; do addIP="$i" echo "$addIP"" ""$addDomain" >> $hostsPath done return 0 fi for i in $addIPs; do addIP="$i" addIPCont=`echo "$hostIPs" | grep "$addIP" | wc -l` if [ "$addIPCont" = "0" ]; then echo "$addIP"" ""$addDomain" >> $hostsPath fi done return 0 } removeHosts() { rmDomain="$1" rmPort="$2" hostsPath="$3" if [ -z "$rmDomain" ]; then echo "Please enter remove domain name!" return 1 fi if [ -z "$rmPort" ]; then echo "Please enter remove domain port!" return 1 fi hostIPs=`grep "$rmDomain" $hostsPath | cut -d" " -f1 | sed 's/ //g'` hostIPsCount=`echo "$hostIPs" | wc -w` if [ "$hostIPsCount" = "0" ]; then echo "$hostsPath did not find a name resolution record" return 1 fi ipList="" for i in $hostIPs; do hostIP="$i" ipTestCount=`wget -t1 -T3 --output-document=/dev/nul "$hostIP":"$rmPort" 2>&1 | grep "failed: Connection timed out" | wc -l` if [ "$ipTestCount" = "1" ] && [ "$ipList" != "" ]; then ipList="$ipList"" ""$hostIP" fi if [ "$ipTestCount" = "1" ] && [ "$ipList" = "" ]; then ipList="$hostIP" fi done for i in $ipList; do rmIP="$i" rmKeyword=`echo "$rmIP" | sed 's/\./\\\\./g'` sed -i -e "/$rmKeyword/d" $hostsPath done return 0 } removeHosts "$domainName" "$domainPort" "$hostsPath" touchIPs=`getTouchIPs "$domainName" "$domainPort"` addHosts "$touchIPs" "$domainName" "$hostsPath"
脚本的设计思路,
– 由于“/etc/hosts”设定的名称解析记录比DNS解析记录的优先级别高(程序使用域名优先从“/etc/hosts”中解析)
– 脚本将联通性正常的名称解析记录输入到“/etc/hosts”实现名称解析过滤功能
– 名称解析记录手动设置范例如下,
vim /etc/hosts
加入经过测试通讯正常的IP地址,
172.217.161.170 fcm.googleapis.com 216.58.200.74 fcm.googleapis.com
脚本的函数作用,
– “getTouchIPs()”函数获取fcm.googleapis.com的IP地址并筛选出联通性正常的IP
– “addHosts()”函数从“getTouchIPs()”取得结果并根据结果并对比“/etc/hosts”记录后添加新的名称解析记录
– “removeHosts()”函数删除“/etc/hosts”中联通性异常的名称解析记录
脚本函数的核心语句,其中获取DNS对应的IP地址使用如下命令,
nslookup fcm.googleapis.com
假设有如下返回,
#... Non-authoritative answer: Name: fcm.googleapis.com Address: 142.250.66.138 Name: fcm.googleapis.com Address: 172.217.161.170 Name: fcm.googleapis.com Address: 216.58.200.74 #...
以上“#…”表示省略,其中测试某个IP的443端口联通性使用如下命令,
wget -t1 -T3 --output-document=/dev/nul 216.58.200.74:443
其中删除“/etc/hosts”包含IP地址“216.58.200.74”关键字的行使用如下命令,
sed -i -e "/216\.58\.200\.74/d" /etc/hosts
其中向“/etc/hosts”添加包含新的名称记录使用如下命令,
echo '216.58.200.74:443 fcm.googleapis.com' >> /etc/hosts
2.2 测试脚本
sh ~/scripts/dnsRecordMaintenance.sh "fcm.googleapis.com" "443" "/etc/hosts"
2.3 配置脚本触发
crontab -e
加入如下触发脚本设置,
*/5 * * * * sh ~/scripts/dnsRecordMaintenance.sh "fcm.googleapis.com" "443" "/etc/hosts"
没有评论