Home | History | Annotate | Download | only in examples
      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 >> /var/log/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