 #!/bin/sh

# generate and check /etc/rc.conf, using ya.subr's network info
# nameservers list (see below PORTERS vriable) must be up to date

# $Id$

#. /etc/ya.subr
. /Berkanavt/webscripts/admscripts/scripts/startup/ya.subr
_init_variables

usage() {
	echo >&2
	echo "Usage: `basename $0` [ip IPADDR NETMASK] [local] [check]" >&2
	echo "Usage: `basename $0` refresh" >&2
	echo >&2
	echo "arguments:" >&2
	echo "      refresh              update ns lists from yr, yr must be up to date, (file $0 must be writable)" >&2
	echo "      ip IPADDR NETMASK    generate conf for specified address and netmask" >&2
	echo "      local                use localhost as first nameserver" >&2
	echo "      check                validate existent /etc/resolv.conf" >&2
}

# autogenerated section. don't manually edit this section! run "$0 refresh" instead
PORTERS="5.255.204.1 5.255.206.1 5.255.212.1 5.255.220.1 5.255.221.1 5.45.194.1 5.45.202.1 5.45.234.65 5.45.234.93 5.45.234.97 5.45.234.98 5.45.236.1 5.45.237.1 5.45.238.1 5.45.239.1 37.140.128.1 37.140.129.1 37.140.152.1 37.140.153.1 37.140.154.1 37.140.155.1 37.140.156.1 37.140.157.1 37.140.158.1 37.140.159.1 37.140.176.1 37.140.177.1 37.140.178.1 37.140.179.1 37.140.184.1 37.140.185.1 37.140.186.1 37.140.187.1 37.9.116.1 37.9.71.1 37.9.76.1 37.9.77.1 37.9.80.1 37.9.81.1 37.9.82.1 37.9.83.1 37.9.84.1 37.9.85.1 37.9.86.1 37.9.87.1 37.9.92.1 37.9.93.1 37.9.94.1 37.9.95.1 77.88.11.65 84.201.134.1 84.201.135.1 84.201.176.1 84.201.177.1 84.201.178.1 84.201.179.1 84.201.182.1 84.201.183.1 84.201.189.250 87.250.237.1 93.158.137.250 93.158.142.31 93.158.143.31 93.158.144.250 93.158.145.250 93.158.146.6 93.158.147.6 93.158.148.250 93.158.149.250 93.158.150.250 93.158.151.250 93.158.164.1 93.158.165.1 93.158.166.1 93.158.167.1 93.158.168.1 93.158.169.1 93.158.170.1 93.158.171.1 93.158.172.1 93.158.173.1 93.158.180.1 93.158.181.1 93.158.182.1 93.158.183.1 93.158.187.1 95.108.128.1 95.108.140.1 95.108.141.1 95.108.142.1 95.108.149.1 95.108.150.1 95.108.151.1 95.108.152.1 95.108.153.1 95.108.154.1 95.108.155.1 95.108.156.1 95.108.157.1 95.108.216.1 95.108.217.1 95.108.218.1 95.108.240.1 95.108.241.1 95.108.243.1 95.108.244.1 95.108.245.1 95.108.246.1 95.108.247.1 95.108.248.1 95.108.249.1 100.43.84.1 130.193.40.1 130.193.41.1 130.193.42.1 130.193.43.1 130.193.48.1 130.193.49.1 130.193.50.1 130.193.51.1 130.193.52.1 130.193.53.1 130.193.54.1 130.193.55.1 130.193.56.1 130.193.57.1 130.193.58.1 130.193.59.1 130.193.63.1 141.8.148.2 141.8.149.2 141.8.179.1 178.154.132.1 178.154.133.1 178.154.134.1 178.154.135.1 178.154.140.1 178.154.141.1 178.154.144.1 178.154.145.1 178.154.146.1 178.154.147.1 178.154.148.1 178.154.149.1 178.154.150.1 178.154.156.1 178.154.157.1 178.154.158.1 178.154.159.1 178.154.160.1 178.154.161.1 178.154.162.1 178.154.163.1 178.154.164.1 178.154.165.1 178.154.167.1 178.154.172.1 178.154.173.1 178.154.174.1 178.154.175.1 178.154.176.1 178.154.177.1 178.154.178.1 178.154.179.1 178.154.182.1 178.154.183.1 178.154.188.65 178.154.193.1 178.154.200.1 178.154.202.1 178.154.203.1 178.154.204.1 178.154.205.1 178.154.206.1 178.154.207.1 178.154.208.1 178.154.209.1 178.154.210.1 178.154.211.1 178.154.212.1 178.154.213.1 178.154.216.1 178.154.217.1 178.154.218.1 178.154.219.1 178.154.220.1 178.154.223.1 178.154.239.193 178.154.243.65 178.154.248.1 178.154.249.1 178.154.250.1 178.154.251.1 178.154.252.1 199.36.241.1 213.180.198.1 213.180.207.1 213.180.214.1"
# end autogenerated section

# ns-cashe.yandex.ru
ya_ns_cache="213.180.205.1"
ya_ns1_server="213.180.193.1"

# one porter calculated to serve /24 network, in spite of it's own netmask may be /23 or /22 or larger
fiction_mask="0xffffff00"

refresh() {
	NEWPORTERS=`for i in \`yr +PORTER LIST\`; do host $i | grep "has address" | awk '{print \$4}'; done | sort -g`
	cp $0 $0.prev \
	&& sed "s/^PORTERS=\".*\"/PORTERS=\"`echo $NEWPORTERS`\"/" $0 > /tmp/resolvconf.new \
	&& mv /tmp/resolvconf.new $0 \
	&& chmod +x $0
}

AND() {
	length=`expr \`echo $1 | wc -m\` - 1`
	for bit in `jot $length`; do 
		echo -n `expr \`echo -n $1 | cut -c $bit\` \& \`echo -n $2 | cut -c $bit\``
	done
}

shuffle() {
	tmp=" $1 "
	newlist=""
	while [ "`echo $tmp | awk '{print NF}'`" != "0" ]; do
		randpos=`jot -r 1 1 \`echo $tmp | awk '{print NF}'\``
		item=`echo $tmp | awk "{print $\"$randpos\"}"`
		newlist="$newlist$item "
		tmp=`echo $tmp | sed "s/$item//g"`
	done
	echo $newlist
}

gen_ipv4_lists() {
	eval `ya_network_info $ip`
	native_net_num=$ya_net_num
	native_dc=$ya_DC
	native_vlan=$ya_VLAN
	native_porters=""
	native_dc_porters=""
	native_vlan_porters=""

	ip_o_1=`echo "obase=2; \`echo $ip | awk -F "." '{print $1}'\`" | bc`
	ip_o_2=`echo "obase=2; \`echo $ip | awk -F "." '{print $2}'\`" | bc`
	ip_o_3=`echo "obase=2; \`echo $ip | awk -F "." '{print $3}'\`" | bc`
	ip_o_4=`echo "obase=2; \`echo $ip | awk -F "." '{print $4}'\`" | bc`

	ip_o_1=`printf "%08d" $ip_o_1`
	ip_o_2=`printf "%08d" $ip_o_2`
	ip_o_3=`printf "%08d" $ip_o_3`
	ip_o_4=`printf "%08d" $ip_o_4`

	case $mask in
		[0-9]*.[0-9]*.[0-9]*.[0-9]*)
			nm_o_1=`echo "ibase=10; obase=2; \`echo $mask | cut -f 1 -d '.'\`" | bc`
			nm_o_2=`echo "ibase=10; obase=2; \`echo $mask | cut -f 2 -d '.'\`" | bc`
			nm_o_3=`echo "ibase=10; obase=2; \`echo $mask | cut -f 3 -d '.'\`" | bc`
			nm_o_4=`echo "ibase=10; obase=2; \`echo $mask | cut -f 4 -d '.'\`" | bc`
		;;
		*)
			# heximal notation (for example 0xfffffe00)	
			nm_o_1=`echo "ibase=16; obase=2; \`echo $mask | cut -c 3-4 | tr a-f A-F\`" | bc`
			nm_o_2=`echo "ibase=16; obase=2; \`echo $mask | cut -c 5-6 | tr a-f A-F\`" | bc`
			nm_o_3=`echo "ibase=16; obase=2; \`echo $mask | cut -c 7-8 | tr a-f A-F\`" | bc`
			nm_o_4=`echo "ibase=16; obase=2; \`echo $mask | cut -c 9-10 | tr a-f A-F\`" | bc`
		;;
	esac

	nm_o_1=`printf "%08d" $nm_o_1`
	nm_o_2=`printf "%08d" $nm_o_2`
	nm_o_3=`printf "%08d" $nm_o_3`
	nm_o_4=`printf "%08d" $nm_o_4`

	native_subnet_o_1=`AND $ip_o_1 $nm_o_1`
	native_subnet_o_2=`AND $ip_o_2 $nm_o_2`
	native_subnet_o_3=`AND $ip_o_3 $nm_o_3`
	native_subnet_o_4=`AND $ip_o_4 $nm_o_4`
	
	#fiction netmask
	fnm_o_1=`echo "ibase=16; obase=2; \`echo $fiction_mask | cut -c 3-4 | tr a-f A-F\`" | bc`
	fnm_o_2=`echo "ibase=16; obase=2; \`echo $fiction_mask | cut -c 5-6 | tr a-f A-F\`" | bc`
	fnm_o_3=`echo "ibase=16; obase=2; \`echo $fiction_mask | cut -c 7-8 | tr a-f A-F\`" | bc`
	fnm_o_4=`echo "ibase=16; obase=2; \`echo $fiction_mask | cut -c 9-10 | tr a-f A-F\`" | bc`
	    
	fnm_o_1=`printf "%08d" $fnm_o_1`
	fnm_o_2=`printf "%08d" $fnm_o_2`
	fnm_o_3=`printf "%08d" $fnm_o_3`
	fnm_o_4=`printf "%08d" $fnm_o_4`
	    
	fict_subnet_o_1=`AND $ip_o_1 $fnm_o_1`
	fict_subnet_o_2=`AND $ip_o_2 $fnm_o_2`
	fict_subnet_o_3=`AND $ip_o_3 $fnm_o_3`
	fict_subnet_o_4=`AND $ip_o_4 $fnm_o_4`
	
	other_porters=$PORTERS
	for porter in $PORTERS; do
		eval `ya_network_info $porter`
		if [ $native_net_num = $ya_net_num ]; then
			
			pip_o_1=`echo "obase=2; \`echo $porter | awk -F "." '{print $1}'\`" | bc`
			pip_o_2=`echo "obase=2; \`echo $porter | awk -F "." '{print $2}'\`" | bc`
			pip_o_3=`echo "obase=2; \`echo $porter | awk -F "." '{print $3}'\`" | bc`
			pip_o_4=`echo "obase=2; \`echo $porter | awk -F "." '{print $4}'\`" | bc`
			
			pip_o_1=`printf "%08d" $pip_o_1`
			pip_o_2=`printf "%08d" $pip_o_2`
			pip_o_3=`printf "%08d" $pip_o_3`
			pip_o_4=`printf "%08d" $pip_o_4`

			porter_subnet_o_1=`AND $pip_o_1 $nm_o_1`
			porter_subnet_o_2=`AND $pip_o_2 $nm_o_2`
			porter_subnet_o_3=`AND $pip_o_3 $nm_o_3`
			porter_subnet_o_4=`AND $pip_o_4 $nm_o_4`
			
			# debug lists
			#echo "nativeip [$ip_o_1] [$ip_o_2] [$ip_o_3] [$ip_o_4]"
			#echo "nativenm [$nm_o_1] [$nm_o_2] [$nm_o_3] [$nm_o_4]"
                        #echo "porterip [$pip_o_1] [$pip_o_2] [$pip_o_3] [$pip_o_4]"
			#echo "nativenw [$native_subnet_o_1] [$native_subnet_o_2] [$native_subnet_o_3] [$native_subnet_o_4]"
			#echo "porternw [$porter_subnet_o_1] [$porter_subnet_o_2] [$porter_subnet_o_3] [$porter_subnet_o_4]"			
			#echo "fictivenm [$fnm_o_1] [$fnm_o_2] [$fnm_o_3] [$fnm_o_4]"
			#echo "fictivenw [$fict_subnet_o_1] [$fict_subnet_o_2] [$fict_subnet_o_3] [$fict_subnet_o_4]"			
			#echo ""
			
			if [ "$native_subnet_o_1" = "$porter_subnet_o_1" ] && [ "$native_subnet_o_2" = "$porter_subnet_o_2" ] &&
			   [ "$native_subnet_o_3" = "$porter_subnet_o_3" ] && [ "$native_subnet_o_4" = "$porter_subnet_o_4" ]; then
			    
			    fict_porter_subnet_o_1=`AND $pip_o_1 $fnm_o_1`
			    fict_porter_subnet_o_2=`AND $pip_o_2 $fnm_o_2`
			    fict_porter_subnet_o_3=`AND $pip_o_3 $fnm_o_3`
			    fict_porter_subnet_o_4=`AND $pip_o_4 $fnm_o_4`

				if [ "$fict_subnet_o_1$fict_subnet_o_2$fict_subnet_o_3$fict_subnet_o_4" = \
					"$fict_porter_subnet_o_1$fict_porter_subnet_o_2$fict_porter_subnet_o_3$fict_porter_subnet_o_4" ]; then
					bestporter="$porter "
					other_porters=`echo $other_porters | sed "s/$porter //g"`
				else
					favorite_porters="$favorite_porters$porter "
					other_porters=`echo $other_porters | sed "s/$porter //g"`
				fi
			else 
				native_porters="$native_porters$porter "
				other_porters=`echo $other_porters | sed "s/$porter //g"`
			fi
		elif [ $native_dc = $ya_DC ] && [ $native_net_num != $ya_net_num ]; then
			native_dc_porters="$native_dc_porters$porter "
			other_porters=`echo $other_porters | sed "s/$porter //g"`
		elif [ $native_vlan = $ya_VLAN ] && [ $native_dc != $ya_DC ]; then
			native_vlan_porters="$native_vlan_porters$porter "
			other_porters=`echo $other_porters | sed "s/$porter //g"`
		fi
	done

	[ "$local_dns" = "YES" ] && local_dns_ip="127.0.0.1 " ||  local_dns_ip=""
	favorite_porters="`shuffle "$favorite_porters"` "
	native_porters="`shuffle "$native_porters"` "
	native_dc_porters="`shuffle "$native_dc_porters"` "
	native_vlan_porters="`shuffle "$native_vlan_porters"` "
	other_porters="`shuffle "$other_porters"` "

	# debug lists
	#echo ""
	#echo "bestporter: [$bestporter]"
	#echo "favorite: [$favorite_porters]" 
	#echo "native: [$native_porters]"
	#echo "native_dc: [$native_dc_porters]"
	#echo "native_vlan: [$native_vlan_porters]"
	#echo "other_porters: [$other_porters]" 

	return 0
}

print_conf() {
	local nslist
#	echo "# Generated `date` by `basename $0` (`echo '$Revision$' | awk '{print $2}'`) for ${shortname:-NXDOMAIN} (inet $ip netmask $mask)"
#	echo "domain yandex.ru"
#	case ${shortname} in
#		porter*|balancer*)
#			echo "nameserver 127.0.0.1"      # host has local dns server
#			echo "nameserver $ya_ns_cache"   # ns-cache.yandex.ru"
#			echo "nameserver $ya_ns1_server"  # ns1.yandex.ru
#		;;
#		*)
			gen_ipv4_lists
			nslist="$local_dns_ip $bestporter $favorite_porters $native_porters $native_dc_porters $native_vlan_porters $other_porters"
#			for ns in `echo ${nslist} | awk '{print $1, $2}'`; do
#				echo "nameserver $ns"
#			done
#			echo "nameserver $ya_ns_cache"   # ns-cache.yandex.ru"
		if [ `uname -s` = "Linux" ]
		then
		        echo "# Generated `date` by `basename $0` (`echo '$Revision$' | awk '{print $2}'`) for ${shortname:-NXDOMAIN} (inet $ip netmask $mask)" > /etc/yp.conf
			printf "
#
# yp.conf       Configuration file for the ypbind process. You can define
#               NIS servers manually here if they can't be found by
#               broadcasting on the local net (which is the default).
#
#               See the manual page of ypbind for the syntax of this file.
#
# IMPORTANT:    For the "ypserver", use IP addresses, or make sure that
#               the host is in /etc/hosts. This file is only interpreted
#               once, and if DNS isn't reachable yet the ypserver cannot
#               be resolved and ypbind won't ever bind to the server.

# ypserver ypserver.network.com
#
" >> /etc/yp.conf
			echo "yandex-search" > /etc/defaultdomain
			for ns in `echo  ${nslist}  | tr -s \ | cut -d \  -f 1-10`; do
				echo "domain yandex-search server `host $ns | awk '{print $5}' | sed "s/\.$//"`" >> /etc/yp.conf
			done
		else
			[ -f /etc/rc.conf.d/ypbind ] || rm /etc/rc.conf.d/ypbind
			echo "nisdomainname=\"yandex-search\"" > /etc/rc.conf.d/nisdomain
			echo "nis_client_enable=\"YES\"" > /etc/rc.conf.d/ypbind
			printf "nis_client_flags=\"-s -m -S yandex-search"  >> /etc/rc.conf.d/ypbind
       			for ns in `echo "$native_dc_porters $native_porters $favorite_porters $bestporter $local_dns_ip" | tr -s \ | cut -d \  -f 1-10`; do
               		printf ",`host $ns | awk '{print $5}' | sed "s/\.$//"`"  >> /etc/rc.conf.d/ypbind
			done
		printf " -ypset\""  >> /etc/rc.conf.d/ypbind
		sed -i.bak '/nis_client/d' /etc/rc.conf
		fi
#		;;
#	esac
#	echo "options  timeout:1 attempts:1"
}

#check_conf() {
#	# validate exist /etc/resolv.conf
#	local ret porter priority_list list ns ns_seq
#	ret=0
#	curr_nameservers=`cat $1 | sed "s/#.*$//g" | awk '$1 == "nameserver" {print $2}' | tr "\n" \ `
#	ns=`echo $curr_nameservers | awk '{print $1}'`
#	ns_seq=0
#	case ${shortname} in
#		porter*|balancer*)
#			# this hosts has predefined conf
#			local_dns_ip=127.0.0.1
#			bestporter=$ya_ns_cache
#			favorite_porters=$ya_ns1_server
#		;;
#		*)
#			gen_ipv4_lists
#		;;
#	esac
#	for priority_list in \$local_dns_ip \$bestporter \$favorite_porters \$native_porters \$native_dc_porters \$native_vlan_porters \$other_porters; do
#		list=`eval echo -n $priority_list`
#		[ -z "$list" ] && continue # skip empty lists
#		echo $list | grep -w $ns 2>/dev/null >/dev/null || { echo "wrong nameserver '$ns', it must be one of '$list'" >&2; ret=1; }  
#		curr_nameservers=`echo $curr_nameservers | sed "s/$ns //"`
#		ns=`echo $curr_nameservers | awk '{print $1}'`
#		ns_seq=`expr $ns_seq + 1`
#		if [ 2 = "$ns_seq" ]; then
#			# check 3-rd (last record)
#			if [ "$ns" = "$ya_ns_cache" ]; then 
#				return $ret 
#			else
#				echo "wrong nameserver '$ns', it must be '$ya_ns_cache' (ns-cache.yandex.ru)" >&2
#				return 1
#			fi
#		fi
#	done
#	return $ret
#}

case "$1" in
     	  ""|local)
#	""|local|check)
		ifn=""
		shortname=`hostname -s`
		if command -v ya_ip_manage >/dev/null && command -v ya_interface_get_active >/dev/null; then
			# using linux compatible functions provided by new ya.subr
			ip=`ya_ip_manage list \`ya_interface_get_active\` | sed "s/[0-9a-zA-Z]*:[0-9a-zA-Z]*//g" | awk '{print $1}'`
			load_networks
			eval `ya_network_info $ip`
			mask="$ya_netmask"
		else
			# using old, BSD only ifconfig method 
			for if_net in `ifconfig -l`; do
				[ X$if_net = Xlo0 ]&& continue
				if [ X`ifconfig $if_net|awk '$1~/status/&&$2=="active" {print "ok"}'` = "Xok" ]; then
					if [ X`ifconfig $if_net|awk '$1=="inet"&&$2~/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {print "ok";exit}'` = "Xok" ]; then
						ifn=$if_net;
						break;
					fi
				fi
			done
			ip=`ifconfig $ifn | awk '$1=="inet" {print $2; exit}'`
			mask=`ifconfig $ifn | awk '$3=="netmask" {print $4; exit}'`
		fi
		[ "$1" = "local" ] && local_dns="YES"
#		if [ "$1" = "check" -o "$2" = "check" ]; then
#			check_conf "/etc/resolv.conf"
#		else
			print_conf
#		fi
		;;
	refresh) 
		refresh
		;;
	ip)
		ip=$2
		mask=$3
		shortname=`host -t A $ip ${ya_ns_cache} | grep '^[0-9][0-9]*' | awk '{print $5}' | sed 's/\..*$//'`
		[ "$4" = "local" ] && local_dns="YES"
		[ -z "$mask" ] && usage && exit
#		if [ check = "$5" -o check = "$4" ]; then 
#			check_conf "/etc/resolv.conf"
#		else
			print_conf
#		fi
		;;
	*)
		usage
		exit 3
		;;
esac
