#!/bin/sh
# dhclient-script for Linux. Dan Halbert, March, 1997.
# Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
# No guarantees about this. I'm a novice at the details of Linux
# networking.

# Notes:

# 0. This script is based on the netbsd script supplied with dhcp-970306.

# 1. ifconfig down apparently deletes all relevant routes and flushes
# the arp cache, so this doesn't need to be done explicitly.

# 2. The alias address handling here has not been tested AT ALL.
# I'm just going by the doc of modern Linux ip aliasing, which uses
# notations like eth0:0, eth0:1, for each alias.

# 3. I have to calculate the network address, and calculate the broadcast
# address if it is not supplied. This might be much more easily done
# by the dhclient C code, and passed on.

# 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious
# of the $1 in its args.

# 'ip' just looks too weird.  /sbin/ip looks less weird.
ip=/sbin/ip
SYNOSETKV=/usr/syno/bin/synosetkeyvalue
SYNONET=/usr/syno/sbin/synonet
SYNONETDTOOL=/usr/syno/sbin/synonetdtool
IPCALC=/bin/ipcalc

SYNO_IPV6_CONF_PREFIX=/etc/sysconfig/networking/ipv6-
SYNO_IPV6_ROUTER_LOCK=/tmp/lock/lock_ipv6_router
SYNO_DHCP_INFO_PREFIX=/etc/dhclient/ipv4/dhcpcd-
MAC_ADDR=`ifconfig $interface | grep HWaddr | awk '{print $5}'`
LOGGER_DHCP="/usr/bin/logger -p user.err -t dhcp-client"

SYNO_DHCP_CLIENT_RESOLV_OPTION_FILE=/etc/resolv.conf.option

. /etc/iproute2/script/gateway-mgt-function

make_resolv_conf() {
	if [ "x$new_domain_name" != "x" -a "x$new_domain_name" != "x$old_domain_name" ]; then
		echo -e "domain\t$new_domain_name" > $SYNO_DHCP_CLIENT_RESOLV_OPTION_FILE
		$SYNONET --dns_update
	fi
}

# this function is the original version of make_resolv_conf()
original_make_resolv_conf() {
	if [ x"$new_domain_name_servers" != x ]; then
		cat /dev/null > /etc/resolv.conf.dhclient
		chmod 644 /etc/resolv.conf.dhclient
		if [ x"$new_domain_search" != x ]; then
			echo search $new_domain_search >> /etc/resolv.conf.dhclient
		elif [ x"$new_domain_name" != x ]; then
			# Note that the DHCP 'Domain Name Option' is really just a domain
			# name, and that this practice of using the domain name option as
			# a search path is both nonstandard and deprecated.
			echo search $new_domain_name >> /etc/resolv.conf.dhclient
		fi
		for nameserver in $new_domain_name_servers; do
			echo nameserver $nameserver >>/etc/resolv.conf.dhclient
		done

		mv /etc/resolv.conf.dhclient /etc/resolv.conf
	elif [ "x${new_dhcp6_name_servers}" != x ] ; then
		cat /dev/null > /etc/resolv.conf.dhclient6
		chmod 644 /etc/resolv.conf.dhclient6

		if [ "x${new_dhcp6_domain_search}" != x ] ; then
			echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6
		fi
		shopt -s nocasematch 
		for nameserver in ${new_dhcp6_name_servers} ; do
			# If the nameserver has a link-local address
			# add a <zone_id> (interface name) to it.
			if	[[ "$nameserver" =~ ^fe80:: ]]
			then
				zone_id="%$interface"
			else
				zone_id=
			fi
			echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6
		done
		shopt -u nocasematch 

		mv /etc/resolv.conf.dhclient6 /etc/resolv.conf
	fi
}

# Must be used on exit.	 Invokes the local dhcp client exit hooks, if any.
exit_with_hooks() {
	exit_status=$1
	if [ -f /etc/dhclient-exit-hooks ]; then
		. /etc/dhclient-exit-hooks
	fi
# probably should do something with exit status of the local script
	exit $exit_status
}

syno_write_info() {
	if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \
		 [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then
		# for /etc/dhclient/ipv4/XXX.info file
		printf \
"IPADDR=$new_ip_address\n"\
"NETMASK=$new_subnet_mask\n"\
"NETWORK=$new_network_number\n"\
"BROADCAST=$new_broadcast_address\n"\
"GATEWAY=$new_routers\n"\
"DOMAIN=$new_domain_name\n"\
"DNS=$new_domain_name_servers\n"\
"DHCPSID=$new_dhcp_server_identifier\n"\
"DHCPGIADDR=\n"\
"DHCPSIADDR=\n"\
"DHCPCHADDR=${MAC_ADDR}\n"\
"DHCPSHADDR=\n"\
"DHCPSNAME=$new_server_name\n"\
"LEASETIME=$new_dhcp_lease_time\n"\
"RENEWALTIME=$new_dhcp_renewal_time\n"\
"REBINDTIME=$new_dhcp_rebinding_time\n"\
"INTERFACE=$interface\n"\
"CLIENTID=${MAC_ADDR}\n" > ${SYNO_DHCP_INFO_PREFIX}${interface}".info"
	fi
}

# Invoke the local dhcp client enter hooks, if they exist.
if [ -f /etc/dhclient-enter-hooks ]; then
	exit_status=0
	. /etc/dhclient-enter-hooks
	# allow the local script to abort processing of this state
	# local script must set exit_status variable to nonzero.
	if [ $exit_status -ne 0 ]; then
		exit $exit_status
	fi
fi

###
### DHCPv4 Handlers
###
if [ x$new_broadcast_address != x ]; then
	new_broadcast_arg="broadcast $new_broadcast_address"
fi
if [ x$old_broadcast_address != x ]; then
	old_broadcast_arg="broadcast $old_broadcast_address"
fi
if [ x$new_subnet_mask != x ]; then
	new_subnet_arg="$new_subnet_mask"
fi
if [ x$old_subnet_mask != x ]; then
	old_subnet_arg="$old_subnet_mask"
fi
if [ x$alias_subnet_mask != x ]; then
	alias_subnet_arg="netmask $alias_subnet_mask"
fi
if [ x$new_interface_mtu != x ]; then
	mtu_arg="mtu $new_interface_mtu"
fi
if [ x$IF_METRIC != x ]; then
	metric_arg="metric $IF_METRIC"
fi

if [ x$reason = xMEDIUM ]; then
	# Linux doesn't do mediums (ok, ok, media).
	exit_with_hooks 0
fi

if [ x$reason = xPREINIT ]; then
	if [ x$alias_ip_address != x ]; then
		# Bring down alias interface. Its routes will disappear too.
		ifconfig $interface:0- inet 0
	fi
	ifconfig $interface up

	# We need to give the kernel some time to get the interface up.
	sleep 1

	exit_with_hooks 0
fi

if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then
	exit_with_hooks 0
fi

if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
	 [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then
	# for /etc/dhcpc/XXX.info file
	syno_write_info

	if [ "xtrue" = "x$SYNO_TEST_ENV" ]; then
		exit_with_hooks 0
	fi
	# we don't modified hostname in DHCP
	#if [ x$current_hostname = x ] || \
	#	 [ x$current_hostname = "x(none)" ] || \
	#	 [ x$current_hostname = xlocalhost ] || \
	#	 [ x$current_hostname = x$old_host_name ]; then
	#	if [ x$new_host_name != x$old_host_name ]; then
	#		hostname "$new_host_name"
	#	fi
	#fi
	if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \
		[ x$alias_ip_address != x$old_ip_address ]; then
		# Possible new alias. Remove old alias.
		ifconfig $interface:0- inet 0
	fi
	#if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then
		# IP address changed. Bringing down the interface will delete all routes,
		# and clear the ARP cache.
		#ifconfig $interface inet 0 down
		# we don't want the interface down
		# because pre hook, we don't clear IP in dhcp
		#ifconfig $interface inet 0.0.0.0
	#fi
	if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \
		 [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then
		if [ -f /tmp/dhcpv4.lease.${interface} ]; then
			cp -f /tmp/dhcpv4.lease.${interface} /etc/dhclient/ipv4/dhcpv4.lease.${interface}
		fi

		#ifconfig $interface inet $new_ip_address $new_subnet_arg \
		#			$new_broadcast_arg $mtu_arg
		ip_prefix=`$IPCALC -p $new_ip_address $new_subnet_arg | cut -d '=' -f 2`
		$SYNONET --set_ip -4 $interface add $new_ip_address/$ip_prefix
		`$LOGGER_DHCP "$interface get new IP $new_ip_address/$ip_prefix"`

		# Add a network route to the computed network address.
		for router in $new_routers; do
			if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then
				route add -host $router dev $interface
			fi
			if [ "x$new_domain_name_servers" != "x" ]; then
				#route add default gw $router $metric_arg dev $interface
				for nameserver in $new_domain_name_servers; do
					${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ${nameserver} ethernet
					break
				done
			else
				# add gateway even their is no given dns
				${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ethernet
			fi
		done
		set_default_gateway_interface
		${SYNONETDTOOL} --refresh-gateway -4

		if [ "x$old_ip_address" != "x" ]; then
			${SYNONETDTOOL} --del-policy-route-rule -4 ${interface}_policy ${interface}  #delete v4 rule
			${SYNONETDTOOL} --disable-route-table  -4 ${interface}
		fi

		${SYNONETDTOOL} --add-policy-route-rule -4 ${interface}_policy ${interface} ${new_ip_address} ${new_subnet_mask} ${new_ip_address}
		${SYNONETDTOOL} --refresh-route-table -4 ${interface} ${new_ip_address}

	else
		# we haven't changed the address, have we changed other options
		# that we wish to update?
		if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then
			# if we've changed routers delete the old and add the new.
			#for router in $old_routers; do
			#	route del default gw $router
			#done
			for router in $new_routers; do
				if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then
					route add -host $router dev $interface
				fi

				if [ "x$new_domain_name_servers" != "x" ]; then
					#route add default gw $router $metric_arg dev $interface
					for nameserver in $new_domain_name_servers; do
						${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ${nameserver} ethernet
						break
					done
				else
					# add gateway even their is no given dns
					${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ethernet
				fi
			done
			set_default_gateway_interface
			${SYNONETDTOOL} --refresh-gateway -4
		fi
	fi
	if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ];
	 then
		ifconfig $interface:0- inet 0
		ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg
		route add -host $alias_ip_address $interface:0
		if [ "x$new_domain_name_servers" != "x" ]; then
			for nameserver in $new_domain_name_servers; do
				${SYNONETDTOOL} --add-gateway-info -4 -2 $interface:0 ${alias_ip_address} ${nameserver}
				break
			done
		else
			# add gateway even their is no given dns
			${SYNONETDTOOL} --add-gateway-info -4 -2 $interface:0 ${alias_ip_address}
		fi
		set_default_gateway_interface
		${SYNONETDTOOL} --refresh-gateway -4
	fi

	enable_multi_gateway=`/bin/get_key_value /etc/synoinfo.conf multi_gateway`
	if [ "xyes" = "x${enable_multi_gateway}" ]; then
		${SYNONETDTOOL} --enable-multi-gateway
	fi

	make_resolv_conf
	exit_with_hooks 0
fi

if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \
	 || [ x$reason = xSTOP ]; then
	if [ x$alias_ip_address != x ]; then
		# Turn off alias interface.
		ifconfig $interface:0- inet 0
	fi
	#if [ x$old_ip_address != x ] && [ "xEXPIRE" != x$reason ] ; then
		# Shut down interface, which will delete routes and clear arp cache.
		# we don't want shutdown interface
		# we don't clear IP in DHCP
		#ifconfig $interface inet 0.0.0.0
	#fi
	if [ x$alias_ip_address != x ]; then
		ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg
		route add -host $alias_ip_address $interface:0
		if [ "x$new_domain_name_servers" != "x" ]; then
			for nameserver in $new_domain_name_servers; do
				${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ${nameserver} ethernet
				break
			done
		else
			# add gateway even their is no given dns
			${SYNONETDTOOL} --add-gateway-info -4 -2 $interface $router ethernet
		fi
		set_default_gateway_interface
		${SYNONETDTOOL} --refresh-gateway -4
	fi
	exit_with_hooks 0
fi

if [ x$reason = xTIMEOUT ]; then
	if [ x$alias_ip_address != x ]; then
		ifconfig $interface:0- inet 0
	fi
###
###	<DSM> #76866 - don't set ip again if TIMEOUT state
###
#	ifconfig $interface inet $new_ip_address $new_subnet_arg \
#					$new_broadcast_arg $mtu_arg
#	set $new_routers
#	if ping -q -c 1 $1; then
#		if [ x$new_ip_address != x$alias_ip_address ] && \
#			[ x$alias_ip_address != x ]; then
#			ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg
#			route add -host $alias_ip_address dev $interface:0
#		fi
#		for router in $new_routers; do
#			if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then
#	route add -host $router dev $interface
#			fi
#			#route add default gw $router $metric_arg dev $interface
#			for nameserver in $new_domain_name_servers; do
#					${SYNONETDTOOL} --add-gateway-info -4 -2 ${interface} $router ${nameserver} ethernet
#			done
#			set_default_gateway_interface
#			${SYNONETDTOOL} --refresh-gateway -4
#		done
#		#make_resolv_conf
#		exit_with_hooks 0
#	fi
	# give him/her a 169.254.x.x in dhclient.c
	#ifconfig $interface inet 0 down
	exit_with_hooks 1
fi

###
### DHCPv6 Handlers
###

if [ x$reason = xPREINIT6 ] ; then
	# Ensure interface is up.
	${ip} link set ${interface} up

	# Remove any stale addresses from aborted clients.
	#${ip} -f inet6 addr flush dev ${interface} scope global permanent

	exit_with_hooks 0
fi

if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
	echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}

	local count=0
	while [ -e "${SYNO_IPV6_ROUTER_LOCK}" -a ${count} -lt 30 ]
	do
		sleep 1
		count=$(($count + 1))
	done

	if [ ${count} -ge 30 ]; then
		exit_with_hooks 1
	fi

	${SYNOSETKV} "${SYNO_IPV6_CONF_PREFIX}${interface}" prefix "${new_ip6_prefix}"
	${SYNONETDTOOL} --apply-new-prefix "${interface}"

	exit_with_hooks 0
fi

if [ x$reason = xBOUND6 ] ; then
	if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
		exit_with_hooks 2;
	fi

	${SYNONET} --set_ip -6 $interface add ${new_ip6_address}/${new_ip6_prefixlen}

	# Check for nameserver options.
	#make_resolv_conf
	if [ "x$new_dhcp6_name_servers" != "x" ]; then
		for nameserver in ${new_dhcp6_name_servers} ; do
			if [ -n ${nameserver} ]; then
				${SYNONETDTOOL} --add-gateway-info -6 -2 ${interface} NULL ${nameserver}
				break
			fi
		done
	else
		# add gateway even their is no given dns
		${SYNONETDTOOL} --add-gateway-info -6 -2 ${interface} NULL
	fi
	set_default_gateway_interface
	${SYNONETDTOOL} --refresh-gateway -6

	enable_multi_gateway=`/bin/get_key_value /etc/synoinfo.conf multi_gateway`
	if [ "xyes" = "x${enable_multi_gateway}" ]; then
		${SYNONETDTOOL} --enable-multi-gateway-v6
	fi

	exit_with_hooks 0
fi

if [ x$reason = xRENEW6 ] || [ x$reason = xREBIND6 ] ; then
	# Nameservers/domains/etc.
	if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] ; then
		if [ "x$new_dhcp6_name_servers" != "x" ]; then
			for nameserver in ${new_dhcp6_name_servers} ; do
				if [ -n ${nameserver} ]; then
					${SYNONETDTOOL} --add-gateway-info -6 -2 ${interface} NULL ${nameserver}
					break
				fi
			done
		else
			# add gateway even their is no given dns
			${SYNONETDTOOL} --add-gateway-info -6 -2 ${interface} NULL
		fi
	enable_multi_gateway=`/bin/get_key_value /etc/synoinfo.conf multi_gateway`
	if [ "xyes" = "x${enable_multi_gateway}" ]; then
		${SYNONETDTOOL} --enable-multi-gateway-v6
	fi
	fi
	set_default_gateway_interface
	${SYNONETDTOOL} --refresh-gateway -6

	if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
		exit_with_hooks 2;
	fi

	${SYNONET} --set_ip -6 $interface add ${new_ip6_address}/${new_ip6_prefixlen}

	# Make sure nothing has moved around on us.

	exit_with_hooks 0
fi

if [ x$reason = xDEPREF6 ] ; then
	if [ x${new_ip6_prefixlen} = x ] ; then
		exit_with_hooks 2;
	fi

	${SYNONET} --set_ip -6 $interface add ${new_ip6_address}/${new_ip6_prefixlen}

	exit_with_hooks 0
fi

if [ x$reason = xEXPIRE6 -o x$reason = xRELEASE6 -o x$reason = xSTOP6 ] ; then
	if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
		exit_with_hooks 2;
	fi

	${SYNONET} --set_ip -6 $interface flush

	exit_with_hooks 0
fi

exit_with_hooks 0
