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 (at] 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 17 exec >> /tmp/DHS.log 2>&1 18 19 echo dhc-script $* reason=$reason 20 set | grep "^\(old_\|new_\|check_\)" 21 22 LOG () { 23 echo LOG $* ; 24 } 25 26 # convert 8bit mask to length 27 # arg: $1 = mask 28 # 29 Mask8ToLen() { 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 # 44 MaskToLen() { 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 # 77 ABCMask () { 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 # 100 ABCMaskLen () { 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 # 127 DelINETAddr () { 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 # 147 AddINETAddr () { 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 # 171 AddDefaultRoutes() { 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 # 186 DelDefaultRoutes() { 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 # 202 PingNode() { 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 # 214 CheckRouterList() { 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 # 236 X-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 # 255 AddStaticRouteList() { 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 # 263 DelStaticRouteList() { 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 # 272 UnsolicitedARP() { 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. 283 DAD() { 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 # 299 UpdateDNS() { 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 335 case $reason in 336 NBI) 337 exit 1 338 ;; 339 340 MEDIUM) 341 exit 0 342 ;; 343 344 PREINIT) 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 358 ARPSEND) 359 exit 0 360 ;; 361 362 ARPCHECK) 363 if DAD "$interface" "$check_ip_address" ; then 364 exit 0 365 fi 366 exit 1 367 ;; 368 369 BOUND|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 393 EXPIRE|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 408 TIMEOUT) 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 ;; 444 esac 445 446 exit 0 447