如何使用Shell脚本筛选DNS记录?

Bash

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"
没有评论

发表回复

Bash
如何用Tigase监控postfix smtp服务?

1 前言 一个问题,一篇文章,一出故事。 笔者生产中的smtp服务器最近因为负载均衡器的路由故障而导 …

Bash
如何用Tigase监控Elasticsearch集群?

1 前言 一个问题,一篇文章,一出故事。 笔者生产中有一套Elasticsearch集群,笔者为了能 …

Bash
如何用Base Shell获取ES集群状态?

1 前言 一个问题,一篇文章,一出故事。 笔者想要通过Base Shell获取Elasticsear …