Linux服务器一般不带图形界面,管理员通常都是通过命令行界面直接操作服务器。在日常的管理运维中,经常需要用到github、gist、githubusercontent等网站上的一些内容,也有时需要用到Google上的一些服务,如Google API之类的。然而这些网站大部分都被GFW防火长城屏蔽掉了,GFW用到的屏蔽手段很多,其中DNS污染就是一种。
PS: GFW防火长城并不是真正要拦截所有人,而是大部分人,要想访问墙外,办法总是有的。
在Linux环境下通过各种形式×××可能并不是最佳实践,最简单的方法是通过修改/etc/hosts文件避免国内DNS污染。
可用的hosts文件可以通过github/hosts项目(https://github.com/racaljk/hosts)获取,也可以从备份地址(https://coding.net/u/scaffrey/p/hosts/git)获取。
本文只是为Linux提供了一套简单的工具,通过这个Shell脚本结合crontab,可以实现自动更新hosts文件。虽然github/hosts项目中也提供了修改的工具,但自己写一个也是不错的,既可以锻炼自己,又可以学习和备忘。
此Shell脚本功能:
解析链接文件,用于增删改工作目录下的其他文件,这个是冗余的可选功能,当前Shell脚本不需要这个功能,但因为这个功能可能在其他脚本中比较重要,暂时罗列在此
echo带色显示,用于为用户提供友好的提示,如一般信息用白色,提示信息用蓝色,错误信息用红色,成功信息用绿色,警告信息用×××等
检查是否是root或者sudo,修改hosts文件需要root权限
检查网络连通性和DNS解析是否正常,如果不正常,做出简单诊断和修改DNS为8.8.4.4和114.114.114.114
根据Linux发行版本的不同执行不同的命令(安装必要的软件包,如git),目前支持RHEL、CentOS、Ubuntu、Debian等版本
从github和备份地址两种途径获取并更改hosts文件
检测hosts文件是否添加成功,用curl google判断
脚本运行效果如下:
脚本最新内容也可以通过github获取:https://github.com/DingGuodong/GoogleHostsFileForLinux
脚本如下:
#!/bin/bash # Public header # ============================================================================================================================= # resolve links - $0 may be a symbolic link PRG="$0" while [ -h "$PRG" ]; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done # Get standard environment variables PRGDIR=`dirname "$PRG"` # echo color function function cecho { # Usage: # cecho -red sometext #Error, Failed # cecho -green sometext # Success # cecho -yellow sometext # Warning # cecho -blue sometext # Debug # cecho -white sometext # info # cecho -n # new line # end while [ "$1" ]; do case "$1" in -normal) color="\033[00m" ;; # -black) color="\033[30;01m" ;; -red) color="\033[31;01m" ;; -green) color="\033[32;01m" ;; -yellow) color="\033[33;01m" ;; -blue) color="\033[34;01m" ;; # -magenta) color="\033[35;01m" ;; # -cyan) color="\033[36;01m" ;; -white) color="\033[37;01m" ;; -n) one_line=1; shift ; continue ;; *) echo -n "$1"; shift ; continue ;; esac shift echo -en "$color" echo -en "$1" echo -en "\033[00m" shift done if [ ! $one_line ]; then echo fi } # end echo color function # echo color function, smarter function echo_r () { #Error, Failed [ $# -ne 1 ] && return 0 echo -e "\033[31m$1\033[0m" } function echo_g () { # Success [ $# -ne 1 ] && return 0 echo -e "\033[32m$1\033[0m" } function echo_y () { # Warning [ $# -ne 1 ] && return 0 echo -e "\033[33m$1\033[0m" } function echo_b () {\ # Debug [ $# -ne 1 ] && return 0 echo -e "\033[34m$1\033[0m" } # end echo color function, smarter WORKDIR=$PRGDIR # end public header # ============================================================================================================================= USER="`id -un`" LOGNAME=$USER if [ $UID -ne 0 ]; then echo "WARNING: Running as a non-root user, \"$LOGNAME\". Functionality may be unavailable. Only root can use some commands or options" fi # Name: replaceLocalHostsFileAgainstGfw.sh # Refer to: https://github.com/racaljk/hosts # Backups: https://coding.net/u/scaffrey/p/hosts/git # define user friendly messages header=" Function: Execute this shell script to access Google, etc easily. Open source software Written by Guodong Ding. Blog: http://dgd2010.blog.51cto.com/ Github: https://github.com/DingGuodong Last updated: 2016-4-19 " check_network_connectivity(){ echo_b "checking network connectivity ... " network_address_to_check=8.8.4.4 stable_network_address_to_check=114.114.114.114 ping_count=2 ping -c $ping_count $network_address_to_check >/dev/null retval=$? if [ $retval -ne 0 ] ; then if ping -c $ping_count $stable_network_address_to_check >/dev/null;then echo_g "network to $stable_network_address_to_check succeed! " echo_y "note: network to $network_address_to_check failed! " elif ! ip route | grep default >/dev/null; then echo_r "network is unreachable, gateway is not set." exit 1 elif ! ping -c2 $(ip route | awk '/default/ {print $3}') >/dev/null; then echo_r "network is unreachable, gateway is unreachable." exit 1 else echo_r "network is blocked! " exit 1 fi elif [ $retval -eq 0 ]; then echo_g "Check network connectivity passed! " fi } check_name_resolve(){ echo_b "checking name resolve ... " target_name_to_resolve="github.com" stable_target_name_to_resolve="www.aliyun.com" ping_count=1 if ! ping -c$ping_count $target_name_to_resolve >/dev/null; then echo_y "name lookup failed for $target_name_to_resolve with $ping_count times " if ping -c$ping_count $stable_target_name_to_resolve >/dev/null; then echo_g "name lookup success for $stable_target_name_to_resolve with $ping_count times " fi [ -f /etc/resolv.conf ] && cp /etc/resolv.conf /etc/resolv.conf$(date +%Y%m%d%H%M%S)~ cat >/etc/resolv.conf< /dev/null 2>&1 command -v "$@" >/dev/null 2>&1 } check_command_can_be_execute(){ command_exists } yum_install_packages(){ echo_b "yum install $@ ..." yum -q -yy install $@ retval=$? if [ $retval -ne 0 ] ; then echo_r "yum install $@ failed! " exit 1 else echo_g "yum install $@ successfully! " fi } apt_get_install_packages(){ echo_b "apt-get install $@ ..." apt-get -qq -y install $@ retval=$? if [ $retval -ne 0 ] ; then echo_r "apt-get install $@ failed! " exit 1 else echo_g "apt-get install $@ successfully! " fi } # Refer: https://get.docker.com/ # 'curl -sSL https://get.docker.com/ | sh' # or: # 'wget -qO- https://get.docker.com/ | sh' # # Check if this is a forked Linux distro check_linux_distribution_forked() { # Check for lsb_release command existence, it usually exists in forked distros if command_exists lsb_release; then # Check if the `-u` option is supported set +e lsb_release -a -u > /dev/null 2>&1 lsb_release_exit_code=$? set -e # Check if the command has exited successfully, it means we're in a forked distro if [ "$lsb_release_exit_code" = "0" ]; then # Print info about current distro cat <<-EOF You're using '$lsb_dist' version '$dist_version'. EOF # Get the upstream release info lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[[:space:]]') dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[[:space:]]') # Print info about upstream distro cat <<-EOF Upstream release is '$lsb_dist' version '$dist_version'. EOF else if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ]; then # We're Debian and don't even know it! lsb_dist=debian dist_version="$(cat /etc/debian_version | sed 's/\/.*//' | sed 's/\..*//')" case "$dist_version" in 8|'Kali Linux 2') dist_version="jessie" ;; 7) dist_version="wheezy" ;; esac fi fi fi } check_linux_distribution(){ # refer to /etc/issue and /etc/*-release maybe more better choice # perform some very rudimentary platform detection lsb_dist='' dist_version='' if command_exists lsb_release; then lsb_dist="$(lsb_release -si)" fi if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")" fi if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then lsb_dist='debian' fi if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then lsb_dist='fedora' fi if [ -z "$lsb_dist" ] && [ -r /etc/oracle-release ]; then lsb_dist='oracleserver' fi if [ -z "$lsb_dist" ]; then if [ -r /etc/centos-release ] || [ -r /etc/redhat-release ]; then lsb_dist='centos' fi fi if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then lsb_dist="$(. /etc/os-release && echo "$ID")" fi lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')" case "$lsb_dist" in ubuntu) if command_exists lsb_release; then dist_version="$(lsb_release --codename | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")" fi ;; debian) dist_version="$(cat /etc/debian_version | sed 's/\/.*//' | sed 's/\..*//')" case "$dist_version" in 8) dist_version="jessie" ;; 7) dist_version="wheezy" ;; esac ;; oracleserver) # need to switch lsb_dist to match yum repo URL lsb_dist="oraclelinux" dist_version="$(rpm -q --whatprovides redhat-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//')" ;; fedora|centos) dist_version="$(rpm -q --whatprovides redhat-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//')" ;; *) if command_exists lsb_release; then dist_version="$(lsb_release --codename | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then dist_version="$(. /etc/os-release && echo "$VERSION_ID")" fi ;; esac # Check if this is a forked Linux distro check_linux_distribution_forked } # end Refer above # refer to LNMP, http://lnmp.org/download.html function Get_OS_Bit(){ if [[ `getconf WORD_BIT` = '32' && `getconf LONG_BIT` = '64' ]] ; then Is_64bit='y' else Is_64bit='n' fi } function Get_Dist_Name(){ if grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then DISTRO='CentOS' PM='yum' elif grep -Eqi "Red Hat Enterprise Linux Server" /etc/issue || grep -Eq "Red Hat Enterprise Linux Server" /etc/*-release; then DISTRO='RHEL' PM='yum' elif grep -Eqi "Aliyun" /etc/issue || grep -Eq "Aliyun" /etc/*-release; then DISTRO='Aliyun' PM='yum' elif grep -Eqi "Fedora" /etc/issue || grep -Eq "Fedora" /etc/*-release; then DISTRO='Fedora' PM='yum' elif grep -Eqi "Debian" /etc/issue || grep -Eq "Debian" /etc/*-release; then DISTRO='Debian' PM='apt' elif grep -Eqi "Ubuntu" /etc/issue || grep -Eq "Ubuntu" /etc/*-release; then DISTRO='Ubuntu' PM='apt' elif grep -Eqi "Raspbian" /etc/issue || grep -Eq "Raspbian" /etc/*-release; then DISTRO='Raspbian' PM='apt' else DISTRO='unknow' fi Get_OS_Bit } function Get_RHEL_Version(){ Get_Dist_Name if [ "${DISTRO}" = "RHEL" ]; then if grep -Eqi "release 5." /etc/redhat-release; then echo "Current Version: RHEL Ver 5" RHEL_Ver='5' elif grep -Eqi "release 6." /etc/redhat-release; then echo "Current Version: RHEL Ver 6" RHEL_Ver='6' elif grep -Eqi "release 7." /etc/redhat-release; then echo "Current Version: RHEL Ver 7" RHEL_Ver='7' fi fi } function Get_ARM(){ if uname -m | grep -Eqi "arm"; then Is_ARM='y' fi } Install_LSB() { if [ "$PM" = "yum" ]; then yum -y install redhat-lsb elif [ "$PM" = "apt" ]; then apt-get update apt-get install -y lsb-release fi } Get_Dist_Version() { Install_LSB eval ${DISTRO}_Version=`lsb_release -rs` eval echo "${DISTRO} \${${DISTRO}_Version}" } # end refer to http://lnmp.org/download.html function get_hosts_file_from_backup_site(){ if ! grep github /etc/hosts >/dev/null; then cp /etc/hosts /etc/hosts$(date +%Y%m%d%H%M%S)~ else rm -f /etc/hosts \cp -f hosts/hosts /etc/hosts fi wget -q https://coding.net/u/scaffrey/p/hosts/git/raw/master/hosts -O /etc/hosts if test $? -eq 0 -a -f /etc/hosts; then echo_g "set hosts file from backup site successfully! " else echo_r "set hosts file from backup site failed! " fi } function get_hosts_file_from_github(){ if [ ! -d hosts ]; then command_exists git && git clone https://github.com/racaljk/hosts.git >/dev/null 2>&1 retval=$? if [ $retval -ne 0 ] ; then echo_r "git clone failed! " get_hosts_file_from_backup_site return else [ -s hosts/hosts ] && echo "git clone successfully! " || exit 1 fi elif [ -d hosts/.git ]; then cd hosts command_exists git && git pull >/dev/null 2>&1 cd .. else echo_r "there was a directory named \"hosts\", failed! " exit 1 fi if ! grep github /etc/hosts >/dev/null && test hosts/hosts -nt /etc/hosts; then cp /etc/hosts /etc/hosts$(date +%Y%m%d%H%M%S)~ \cp -f hosts/hosts /etc/hosts else rm -f /etc/hosts \cp -f hosts/hosts /etc/hosts fi } function validate_network_to_outside(){ echo_b "validating hosts file ... " http_code=$(curl -o /dev/null -m 10 --connect-timeout 10 -s -w "%{http_code}" https://www.google.com.hk/) if [ $http_code -ne 200 ]; then echo_g "Replace hosts file succeeded! " echo echo_g "Now you can access Google, etc easily! " else echo_r "replace hosts file failed! " exit 1 fi } # main function # Run setup for each distro accordingly, install git here. cat -< 一些有用的参考:
修改 hosts 文件的原理是什么? https://www.zhihu.com/question/19782572
github/hosts项目wiki https://github.com/racaljk/hosts/wiki
tag: Google hosts,Linux访问Google,Linux×××
--end--