dhclient-script 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #!/bin/sh
  2. # dhclient-script for Linux. Dan Halbert, March, 1997.
  3. # Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
  4. # Modified for Debian. Matt Zimmerman and Eloy Paris, December 2003
  5. # Modified to remove useless tests for antiquated kernel versions that
  6. # this doesn't even work with anyway, and introduces a dependency on /usr
  7. # being mounted, which causes cosmetic errors on hosts that NFS mount /usr
  8. # Andrew Pollock, February 2005
  9. # Modified to work on point-to-point links. Andrew Pollock, June 2005
  10. # Modified to support passing the parameters called with to the hooks. Andrew Pollock, November 2005
  11. # The alias handling in here probably still sucks. -mdz
  12. # wait for given file to be writable
  13. wait_for_rw() {
  14. local file=$1
  15. # Find out whether we are going to mount / rw
  16. exec 9>&0 </etc/fstab
  17. rootmode=rw
  18. while read dev mnt type opts dump pass junk; do
  19. [ "$mnt" != / ] && continue
  20. case "$opts" in
  21. ro|ro,*|*,ro|*,ro,*)
  22. rootmode=ro
  23. ;;
  24. esac
  25. done
  26. exec 0>&9 9>&-
  27. # Wait for $file to become writable
  28. if [ "$rootmode" = "rw" ]; then
  29. while ! { : >> "$file"; } 2>/dev/null; do
  30. sleep 0.1
  31. done
  32. fi
  33. }
  34. # update /etc/resolv.conf based on received values
  35. make_resolv_conf() {
  36. local new_resolv_conf
  37. # DHCPv4
  38. if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||
  39. [ -n "$new_domain_name_servers" ]; then
  40. resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
  41. resolv_conf="/etc/resolv.conf"
  42. new_resolv_conf="${resolv_conf}.dhclient-new.$$"
  43. wait_for_rw "$new_resolv_conf"
  44. rm -f $new_resolv_conf
  45. if [ -n "$new_domain_name" ]; then
  46. echo domain ${new_domain_name%% *} >>$new_resolv_conf
  47. fi
  48. if [ -n "$new_domain_search" ]; then
  49. if [ -n "$new_domain_name" ]; then
  50. domain_in_search_list=""
  51. for domain in $new_domain_search; do
  52. if [ "$domain" = "${new_domain_name}" ] ||
  53. [ "$domain" = "${new_domain_name}." ]; then
  54. domain_in_search_list="Yes"
  55. fi
  56. done
  57. if [ -z "$domain_in_search_list" ]; then
  58. new_domain_search="$new_domain_name $new_domain_search"
  59. fi
  60. fi
  61. echo "search ${new_domain_search}" >> $new_resolv_conf
  62. elif [ -n "$new_domain_name" ]; then
  63. echo "search ${new_domain_name}" >> $new_resolv_conf
  64. fi
  65. if [ -n "$new_domain_name_servers" ]; then
  66. for nameserver in $new_domain_name_servers; do
  67. echo nameserver $nameserver >>$new_resolv_conf
  68. done
  69. else # keep 'old' nameservers
  70. sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf
  71. fi
  72. if [ -f $resolv_conf ]; then
  73. chown --reference=$resolv_conf $new_resolv_conf
  74. chmod --reference=$resolv_conf $new_resolv_conf
  75. fi
  76. mv -f $new_resolv_conf $resolv_conf
  77. # DHCPv6
  78. elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then
  79. resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
  80. resolv_conf="/etc/resolv.conf"
  81. new_resolv_conf="${resolv_conf}.dhclient-new.$$"
  82. wait_for_rw "$new_resolv_conf"
  83. rm -f $new_resolv_conf
  84. if [ -n "$new_dhcp6_domain_search" ]; then
  85. echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf
  86. fi
  87. if [ -n "$new_dhcp6_name_servers" ]; then
  88. for nameserver in $new_dhcp6_name_servers; do
  89. # append %interface to link-local-address nameservers
  90. if [ "${nameserver##fe80::}" != "$nameserver" ] ||
  91. [ "${nameserver##FE80::}" != "$nameserver" ]; then
  92. nameserver="${nameserver}%${interface}"
  93. fi
  94. echo nameserver $nameserver >>$new_resolv_conf
  95. done
  96. else # keep 'old' nameservers
  97. sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf
  98. fi
  99. if [ -f $resolv_conf ]; then
  100. chown --reference=$resolv_conf $new_resolv_conf
  101. chmod --reference=$resolv_conf $new_resolv_conf
  102. fi
  103. mv -f $new_resolv_conf $resolv_conf
  104. fi
  105. }
  106. # set host name
  107. set_hostname() {
  108. if [ -n "$new_host_name" ]; then
  109. local current_hostname=$(hostname)
  110. # current host name is empty, '(none)' or 'localhost' or differs from new one from DHCP
  111. if [ -z "$current_hostname" ] ||
  112. [ "$current_hostname" = '(none)' ] ||
  113. [ "$current_hostname" = 'localhost' ] ||
  114. [ "$current_hostname" = "$old_host_name" ]; then
  115. if [ "$new_host_name" != "$current_host_name" ]; then
  116. hostname "$new_host_name"
  117. fi
  118. fi
  119. fi
  120. }
  121. # run given script
  122. run_hook() {
  123. local script="$1"
  124. local exit_status=0
  125. if [ -f $script ]; then
  126. . $script
  127. exit_status=$?
  128. fi
  129. if [ -n "$exit_status" ] && [ "$exit_status" -ne 0 ]; then
  130. logger -p daemon.err "$script returned non-zero exit status $exit_status"
  131. fi
  132. return $exit_status
  133. }
  134. # run scripts in given directory
  135. run_hookdir() {
  136. local dir="$1"
  137. local exit_status=0
  138. if [ -d "$dir" ]; then
  139. for script in $(run-parts --list $dir); do
  140. run_hook $script
  141. exit_status=$((exit_status|$?))
  142. done
  143. fi
  144. return $exit_status
  145. }
  146. # Must be used on exit. Invokes the local dhcp client exit hooks, if any.
  147. exit_with_hooks() {
  148. local exit_status=$1
  149. # Source the documented exit-hook script, if it exists
  150. if ! run_hook /etc/dhcp/dhclient-exit-hooks; then
  151. exit_status=$?
  152. fi
  153. # Now run scripts in the Debian-specific directory.
  154. if ! run_hookdir /etc/dhcp/dhclient-exit-hooks.d; then
  155. exit_status=$?
  156. fi
  157. exit $exit_status
  158. }
  159. # The 576 MTU is only used for X.25 and dialup connections
  160. # where the admin wants low latency. Such a low MTU can cause
  161. # problems with UDP traffic, among other things. As such,
  162. # disallow MTUs from 576 and below by default, so that broken
  163. # MTUs are ignored, but higher stuff is allowed (1492, 1500, etc).
  164. if [ -z "$new_interface_mtu" ] || [ "$new_interface_mtu" -le 576 ]; then
  165. new_interface_mtu=''
  166. fi
  167. # The action starts here
  168. # Invoke the local dhcp client enter hooks, if they exist.
  169. run_hook /etc/dhcp/dhclient-enter-hooks
  170. run_hookdir /etc/dhcp/dhclient-enter-hooks.d
  171. # Execute the operation
  172. case "$reason" in
  173. ### DHCPv4 Handlers
  174. MEDIUM|ARPCHECK|ARPSEND)
  175. # Do nothing
  176. ;;
  177. PREINIT)
  178. # The DHCP client is requesting that an interface be
  179. # configured as required in order to send packets prior to
  180. # receiving an actual address. - dhclient-script(8)
  181. # ensure interface is up
  182. ip link set dev ${interface} up
  183. if [ -n "$alias_ip_address" ]; then
  184. # flush alias IP from interface
  185. ip -4 addr flush dev ${interface} label ${interface}:0
  186. fi
  187. ;;
  188. BOUND|RENEW|REBIND|REBOOT)
  189. set_hostname
  190. if [ -n "$old_ip_address" ] && [ -n "$alias_ip_address" ] &&
  191. [ "$alias_ip_address" != "$old_ip_address" ]; then
  192. # alias IP may have changed => flush it
  193. ip -4 addr flush dev ${interface} label ${interface}:0
  194. fi
  195. if [ -n "$old_ip_address" ] &&
  196. [ "$old_ip_address" != "$new_ip_address" ]; then
  197. # leased IP has changed => flush it
  198. ip -4 addr flush dev ${interface} label ${interface}
  199. fi
  200. if [ -z "$old_ip_address" ] ||
  201. [ "$old_ip_address" != "$new_ip_address" ] ||
  202. [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then
  203. # new IP has been leased or leased IP changed => set it
  204. ip -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
  205. ${new_broadcast_address:+broadcast $new_broadcast_address} \
  206. ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
  207. ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
  208. dev ${interface} label ${interface}
  209. if [ -n "$new_interface_mtu" ]; then
  210. # set MTU
  211. ip link set dev ${interface} mtu ${new_interface_mtu}
  212. fi
  213. # if we have $new_rfc3442_classless_static_routes then we have to
  214. # ignore $new_routers entirely
  215. if [ ! "$new_rfc3442_classless_static_routes" ]; then
  216. # set if_metric if IF_METRIC is set or there's more than one router
  217. if_metric="$IF_METRIC"
  218. if [ "${new_routers%% *}" != "${new_routers}" ]; then
  219. if_metric=${if_metric:-1}
  220. fi
  221. # Is the interface part of a VRF?
  222. # inspired by https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964264
  223. vrf_table="$(ip -d link show dev ${interface} | awk '/vrf_slave/ { print $3 }')"
  224. vrf_cfg=""
  225. if [ "${vrf_table}" ]; then
  226. vrf_cfg="table ${vrf_table}"
  227. fi
  228. for router in $new_routers; do
  229. if [ "$new_subnet_mask" = "255.255.255.255" ]; then
  230. # point-to-point connection => set explicit route
  231. ip -4 route add ${router} dev $interface $vrf_cfg >/dev/null 2>&1
  232. fi
  233. # set default route
  234. ip -4 route add default via ${router} dev ${interface} $vrf_cfg \
  235. ${if_metric:+metric $if_metric} >/dev/null 2>&1
  236. if [ -n "$if_metric" ]; then
  237. if_metric=$((if_metric+1))
  238. fi
  239. done
  240. fi
  241. else # RENEW||REBIND
  242. ip -4 addr change ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
  243. ${new_broadcast_address:+broadcast $new_broadcast_address} \
  244. ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
  245. ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
  246. dev ${interface} label ${interface}
  247. fi
  248. if [ -n "$alias_ip_address" ] &&
  249. [ "$new_ip_address" != "$alias_ip_address" ]; then
  250. # separate alias IP given, which may have changed
  251. # => flush it, set it & add host route to it
  252. ip -4 addr flush dev ${interface} label ${interface}:0
  253. ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
  254. dev ${interface} label ${interface}:0
  255. ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
  256. fi
  257. # update /etc/resolv.conf
  258. make_resolv_conf
  259. ;;
  260. EXPIRE|FAIL|RELEASE|STOP)
  261. if [ -n "$alias_ip_address" ]; then
  262. # flush alias IP
  263. ip -4 addr flush dev ${interface} label ${interface}:0
  264. fi
  265. if [ -n "$old_ip_address" ]; then
  266. # flush leased IP
  267. ip -4 addr flush dev ${interface} label ${interface}
  268. fi
  269. if [ -n "$alias_ip_address" ]; then
  270. # alias IP given => set it & add host route to it
  271. ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
  272. dev ${interface} label ${interface}:0
  273. ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
  274. fi
  275. ;;
  276. TIMEOUT)
  277. if [ -n "$alias_ip_address" ]; then
  278. # flush alias IP
  279. ip -4 addr flush dev ${interface} label ${interface}:0
  280. fi
  281. # set IP from recorded lease
  282. ip -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
  283. ${new_broadcast_address:+broadcast $new_broadcast_address} \
  284. ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
  285. ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
  286. dev ${interface} label ${interface}
  287. if [ -n "$new_interface_mtu" ]; then
  288. # set MTU
  289. ip link set dev ${interface} mtu ${new_interface_mtu}
  290. fi
  291. # if there is no router recorded in the lease or the 1st router answers pings
  292. if [ -z "$new_routers" ] || ping -q -c 1 "${new_routers%% *}"; then
  293. # if we have $new_rfc3442_classless_static_routes then we have to
  294. # ignore $new_routers entirely
  295. if [ ! "$new_rfc3442_classless_static_routes" ]; then
  296. if [ -n "$alias_ip_address" ] &&
  297. [ "$new_ip_address" != "$alias_ip_address" ]; then
  298. # separate alias IP given => set up the alias IP & add host route to it
  299. ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
  300. dev ${interface} label ${interface}:0
  301. ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
  302. fi
  303. # set if_metric if IF_METRIC is set or there's more than one router
  304. if_metric="$IF_METRIC"
  305. if [ "${new_routers%% *}" != "${new_routers}" ]; then
  306. if_metric=${if_metric:-1}
  307. fi
  308. # set default route
  309. for router in $new_routers; do
  310. ip -4 route add default via ${router} dev ${interface} \
  311. ${if_metric:+metric $if_metric} >/dev/null 2>&1
  312. if [ -n "$if_metric" ]; then
  313. if_metric=$((if_metric+1))
  314. fi
  315. done
  316. fi
  317. # update /etc/resolv.conf
  318. make_resolv_conf
  319. else
  320. # flush all IPs from interface
  321. ip -4 addr flush dev ${interface}
  322. exit_with_hooks 2
  323. fi
  324. ;;
  325. ### DHCPv6 Handlers
  326. # TODO handle prefix change: ?based on ${old_ip6_prefix} and ${new_ip6_prefix}?
  327. PREINIT6)
  328. # ensure interface is up
  329. ip link set ${interface} up
  330. # flush any stale global permanent IPs from interface
  331. ip -6 addr flush dev ${interface} scope global permanent
  332. ;;
  333. BOUND6|RENEW6|REBIND6)
  334. if [ "${new_ip6_address}" ]; then
  335. # set leased IP
  336. ip -6 addr replace ${new_ip6_address} \
  337. dev ${interface} scope global valid_lft ${new_max_life} \
  338. preferred_lft ${new_preferred_life}
  339. fi
  340. # update /etc/resolv.conf
  341. if [ "${reason}" = BOUND6 ] ||
  342. [ "${new_dhcp6_name_servers}" != "${old_dhcp6_name_servers}" ] ||
  343. [ "${new_dhcp6_domain_search}" != "${old_dhcp6_domain_search}" ]; then
  344. make_resolv_conf
  345. fi
  346. ;;
  347. DEPREF6)
  348. # set preferred lifetime of leased IP to 0
  349. ip -6 addr change ${cur_ip6_address} \
  350. dev ${interface} scope global preferred_lft 0
  351. ;;
  352. EXPIRE6|RELEASE6|STOP6)
  353. if [ -z "${old_ip6_address}" ]; then
  354. exit_with_hooks 2
  355. fi
  356. # delete leased IP
  357. ip -6 addr del ${old_ip6_address} \
  358. dev ${interface}
  359. ;;
  360. esac
  361. exit_with_hooks 0