1#!/bin/bash 2# 3# dhclient-script for Linux. 4# 5# This program is free software; you can redistribute it and/or 6# modify it under the terms of the GNU General Public License 7# as published by the Free Software Foundation; either version 8# 2 of the License, or (at your option) any later version. 9# 10# Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 11# 12# Probably, I did not understand, what this funny feature as "alias" 13# means exactly. For now I suppose, that it is a static address, which 14# we should install and preserve. 15# 16 17exec >> /var/log/DHS.log 2>&1 18 19echo dhc-script $* reason=$reason 20set | grep "^\(old_\|new_\|check_\)" 21 22LOG () { 23 echo LOG $* ; 24} 25 26# convert 8bit mask to length 27# arg: $1 = mask 28# 29Mask8ToLen() { 30 local l=0; 31 32 while [ $l -le 7 ]; do 33 if [ $[ ( 1 << $l ) + $1 ] -eq 256 ]; then 34 return $[ 8 - $l ] 35 fi 36 l=$[ $l + 1 ] 37 done 38 return 0; 39} 40 41# convert inet dotted quad mask to length 42# arg: $1 = dotquad mask 43# 44MaskToLen() { 45 local masklen=0 46 local mask8=$1 47 48 case $1 in 49 0.0.0.0) 50 return 0; 51 ;; 52 255.*.0.0) 53 masklen=8 54 mask8=${mask8#255.} 55 mask8=${mask8%.0.0} 56 ;; 57 255.255.*.0) 58 masklen=16 59 mask8=${mask8#255.255.} 60 mask8=${mask8%.0} 61 ;; 62 255.255.255.*) 63 masklen=24 64 mask8=${mask8#255.255.255.} 65 ;; 66 *) 67 return 255 68 ;; 69 esac 70 Mask8ToLen $mask8 71 return $[ $? + $masklen ] 72} 73 74# calculate ABC "natural" mask 75# arg: $1 = dotquad address 76# 77ABCMask () { 78 local class; 79 80 class=${1%%.*} 81 82 if [ "$1" = "255.255.255.255" ]; then 83 echo $1 84 elif [ "$1" = "0.0.0.0" ]; then 85 echo $1 86 elif [ $class -ge 224 ]; then 87 echo 240.0.0.0 88 elif [ $class -ge 192 ]; then 89 echo 255.255.255.0 90 elif [ $class -ge 128 ]; then 91 echo 255.255.0.0 92 else 93 echo 255.0.0.0 94 fi 95} 96 97# calculate ABC "natural" mask length 98# arg: $1 = dotquad address 99# 100ABCMaskLen () { 101 local class; 102 103 class=${1%%.*} 104 105 if [ "$1" = "255.255.255.255" ]; then 106 return 32 107 elif [ "$1" = "0.0.0.0" ]; then 108 return 0 109 elif [ $class -ge 224 ]; then 110 return 4; 111 elif [ $class -ge 192 ]; then 112 return 24; 113 elif [ $class -ge 128 ]; then 114 return 16; 115 else 116 return 8; 117 fi 118} 119 120# Delete IP address 121# args: $1 = interface 122# $2 = address 123# $3 = mask 124# $4 = broadcast 125# $5 = label 126# 127DelINETAddr () { 128 local masklen=32 129 local addrid=$1 130 131 LOG DelINETAddr $* 132 133 if [ "$5" ]; then 134 addrid=$addrid:$5 135 fi 136 LOG ifconfig $addrid down 137 ifconfig $addrid down 138} 139 140# Add IP address 141# args: $1 = interface 142# $2 = address 143# $3 = mask 144# $4 = broadcast 145# $5 = label 146# 147AddINETAddr () { 148 local mask_arg 149 local brd_arg 150 local addrid=$1 151 152 LOG AddINETAddr $* 153 154 if [ "$5" ]; then 155 addrid=$addrid:$5 156 fi 157 if [ "$3" ]; then 158 mask_arg="netmask $3" 159 fi 160 if [ "$4" ]; then 161 brd_arg="broadcast $4" 162 fi 163 164 LOG ifconfig $addrid $2 $mask_arg $brd_arg up 165 ifconfig $addrid $2 $mask_arg $brd_arg up 166} 167 168# Add default routes 169# args: $1 = routers list 170# 171AddDefaultRoutes() { 172 local router 173 174 if [ "$1" ]; then 175 LOG AddDefaultRoutes $* 176 for router in $1; do 177 LOG route add default gw $router 178 route add default gw $router 179 done ; 180 fi 181} 182 183# Delete default routes 184# args: $1 = routers list 185# 186DelDefaultRoutes() { 187 local router 188 189 if [ "$1" ]; then 190 LOG DelDefaultRoutes $* 191 192 for router in $1; do 193 LOG route del default gw $router 194 route del default gw $router 195 done 196 fi 197} 198 199# ping a host 200# args: $1 = dotquad address of the host 201# 202PingNode() { 203 LOG PingNode $* 204 if ping -q -c 1 -w 2 $1 ; then 205 return 0; 206 fi 207 return 1; 208} 209 210# Check (and add route, if alive) default routers 211# args: $1 = routers list 212# returns: 0 if at least one router is alive. 213# 214CheckRouterList() { 215 local router 216 local succeed=1 217 218 LOG CheckRouterList $* 219 220 for router in $1; do 221 if PingNode $router ; then 222 succeed=0 223 route add default gw $router 224 fi 225 done 226 return $succeed 227} 228 229# Delete/create static routes. 230# args: $1 = operation (del/add) 231# $2 = routes list in format "dst1 nexthop1 dst2 ..." 232# 233# BEWARE: this feature of DHCP is obsolete, because does not 234# support subnetting. 235# 236X-StaticRouteList() { 237 local op=$1 238 local lst="$2" 239 local masklen 240 241 LOG X-StaticRouteList $* 242 243 if [ "$lst" ]; then 244 set $lst 245 while [ $# -gt 1 ]; do 246 route $op -net $1 netmask `ABCMask "$1"` gw $2 247 shift; shift; 248 done 249 fi 250} 251 252# Create static routes. 253# arg: $1 = routes list in format "dst1 nexthop1 dst2 ..." 254# 255AddStaticRouteList() { 256 LOG AddStaticRouteList $* 257 X-StaticRouteList add "$1" 258} 259 260# Delete static routes. 261# arg: $1 = routes list in format "dst1 nexthop1 dst2 ..." 262# 263DelStaticRouteList() { 264 LOG DelStaticRouteList $* 265 X-StaticRouteList del "$1" 266} 267 268# Broadcast unsolicited ARP to update neighbours' caches. 269# args: $1 = interface 270# $2 = address 271# 272UnsolicitedARP() { 273 if [ -f /sbin/arping ]; then 274 /sbin/arping -A -c 1 -I "$1" "$2" & 275 (sleep 2 ; /sbin/arping -U -c 1 -I "$1" "$2" ) & 276 fi 277} 278 279# Duplicate address detection. 280# args: $1 = interface 281# $2 = test address 282# returns: 0, if DAD succeeded. 283DAD() { 284 if [ -f /sbin/arping ]; then 285 /sbin/arping -c 2 -w 3 -D -I "$1" "$2" 286 return $? 287 fi 288 return 0 289} 290 291 292# Setup resolver. 293# args: NO 294# domain and nameserver list are passed in global variables. 295# 296# NOTE: we try to be careful and not to break user supplied resolv.conf. 297# The script mangles it, only if it has dhcp magic signature. 298# 299UpdateDNS() { 300 local nameserver 301 local idstring="#### Generated by DHCPCD" 302 303 LOG UpdateDNS $* 304 305 if [ "$new_domain_name" = "" -a "$new_domain_name_servers" = "" ]; then 306 return 0; 307 fi 308 309 echo $idstring > /etc/resolv.conf.dhcp 310 if [ "$new_domain_name" ]; then 311 echo search $new_domain_name >> /etc/resolv.conf.dhcp 312 fi 313 echo options ndots:1 >> /etc/resolv.conf.dhcp 314 315 if [ "$new_domain_name_servers" ]; then 316 for nameserver in $new_domain_name_servers; do 317 echo nameserver $nameserver >> /etc/resolv.conf.dhcp 318 done 319 else 320 echo nameserver 127.0.0.1 >> /etc/resolv.conf.dhcp 321 fi 322 323 if [ -f /etc/resolv.conf ]; then 324 if [ "`head -1 /etc/resolv.conf`" != "$idstring" ]; then 325 return 0 326 fi 327 if [ "$old_domain_name" = "$new_domain_name" -a 328 "$new_domain_name_servers" = "$old_domain_name_servers" ]; then 329 return 0 330 fi 331 fi 332 mv /etc/resolv.conf.dhcp /etc/resolv.conf 333} 334 335case $reason in 336NBI) 337 exit 1 338 ;; 339 340MEDIUM) 341 exit 0 342 ;; 343 344PREINIT) 345 ifconfig $interface:dhcp down 346 ifconfig $interface:dhcp1 down 347 if [ -d /proc/sys/net/ipv4/conf/$interface ]; then 348 ifconfig $interface:dhcp 10.10.10.10 netmask 255.255.255.255 349 ifconfig $interface:dhcp down 350 if [ -d /proc/sys/net/ipv4/conf/$interface ]; then 351 LOG The interface $interface already configured. 352 fi 353 fi 354 ifconfig $interface:dhcp up 355 exit 0 356 ;; 357 358ARPSEND) 359 exit 0 360 ;; 361 362ARPCHECK) 363 if DAD "$interface" "$check_ip_address" ; then 364 exit 0 365 fi 366 exit 1 367 ;; 368 369BOUND|RENEW|REBIND|REBOOT) 370 if [ "$old_ip_address" -a "$alias_ip_address" -a \ 371 "$alias_ip_address" != "$old_ip_address" ]; then 372 DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 373 fi 374 if [ "$old_ip_address" -a "$old_ip_address" != "$new_ip_address" ]; then 375 DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp 376 DelDefaultRoutes "$old_routers" 377 DelStaticRouteList "$old_static_routes" 378 fi 379 if [ "$old_ip_address" = "" -o "$old_ip_address" != "$new_ip_address" -o \ 380 "$reason" = "BOUND" -o "$reason" = "REBOOT" ]; then 381 AddINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp 382 AddStaticRouteList "$new_static_routes" 383 AddDefaultRoutes "$new_routers" 384 UnsolicitedARP "$interface" "$new_ip_address" 385 fi 386 if [ "$new_ip_address" != "$alias_ip_address" -a "$alias_ip_address" ]; then 387 AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 388 fi 389 UpdateDNS 390 exit 0 391 ;; 392 393EXPIRE|FAIL) 394 if [ "$alias_ip_address" ]; then 395 DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 396 fi 397 if [ "$old_ip_address" ]; then 398 DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp 399 DelDefaultRoutes "$old_routers" 400 DelStaticRouteList "$old_static_routes" 401 fi 402 if [ "$alias_ip_address" ]; then 403 AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 404 fi 405 exit 0 406 ;; 407 408TIMEOUT) 409 if [ "$alias_ip_address" ]; then 410 DelINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 411 fi 412# Seems, <null address> means, that no more old leases found. 413# Or does it mean bug in dhcpcd? 8) Fail for now. 414 if [ "$new_ip_address" = "<null address>" ]; then 415 if [ "$old_ip_address" ]; then 416 DelINETAddr "$interface" "$old_ip_address" "$old_subnet_mask" "$old_broadcast_address" dhcp 417 fi 418 if [ "$alias_ip_address" ]; then 419 AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 420 fi 421 exit 1 422 fi 423 if DAD "$interface" "$new_ip_address" ; then 424 AddINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp 425 UnsolicitedARP "$interface" "$new_ip_address" 426 if [ "$alias_ip_address" -a "$alias_ip_address" != "$new_ip_address" ]; then 427 AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 428 UnsolicitedARP "$interface" "$alias_ip_address" 429 fi 430 if CheckRouterList "$new_routers" ; then 431 AddStaticRouteList "$new_static_routes" 432 UpdateDNS 433 exit 0 434 fi 435 fi 436 DelINETAddr "$interface" "$new_ip_address" "$new_subnet_mask" "$new_broadcast_address" dhcp 437 DelDefaultRoutes "$old_routers" 438 DelStaticRouteList "$old_static_routes" 439 if [ "$alias_ip_address" ]; then 440 AddINETAddr "$interface" "$alias_ip_address" "$alias_subnet_mask" "$alias_broadcast_address" dhcp1 441 fi 442 exit 1 443 ;; 444esac 445 446exit 0 447