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